home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / shells / zsh-3.0-p / zsh-3 / zsh-3.0-pre3 / Src / zle_tricky.c < prev    next >
C/C++ Source or Header  |  1996-07-14  |  103KB  |  3,978 lines

  1. /*
  2.  * $Id: zle_tricky.c,v 2.64 1996/07/13 20:26:35 hzoli Exp $
  3.  *
  4.  * zle_tricky.c - expansion and completion
  5.  *
  6.  * This file is part of zsh, the Z shell.
  7.  *
  8.  * Copyright (c) 1992-1996 Paul Falstad
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and its documentation for any purpose, provided that the
  14.  * above copyright notice and the following two paragraphs appear in
  15.  * all copies of this software.
  16.  *
  17.  * In no event shall Paul Falstad or the Zsh Development Group be liable
  18.  * to any party for direct, indirect, special, incidental, or consequential
  19.  * damages arising out of the use of this software and its documentation,
  20.  * even if Paul Falstad and the Zsh Development Group have been advised of
  21.  * the possibility of such damage.
  22.  *
  23.  * Paul Falstad and the Zsh Development Group specifically disclaim any
  24.  * warranties, including, but not limited to, the implied warranties of
  25.  * merchantability and fitness for a particular purpose.  The software
  26.  * provided hereunder is on an "as is" basis, and Paul Falstad and the
  27.  * Zsh Development Group have no obligation to provide maintenance,
  28.  * support, updates, enhancements, or modifications.
  29.  *
  30.  */
  31.  
  32. #define ZLE
  33. #include "zsh.h"
  34.  
  35. /* The main part of ZLE maintains the line being edited as binary data, *
  36.  * but here, where we interface with the lexer and other bits of zsh,   *
  37.  * we need the line metafied.  The technique used is quite simple: on   *
  38.  * entry to the expansion/completion system, we metafy the line in      *
  39.  * place, adjusting ll and cs to match.  All completion and expansion   *
  40.  * is done on the metafied line.  Immediately before returning, the     *
  41.  * line is unmetafied again, changing ll and cs back.  (ll and cs might *
  42.  * have changed during completion, so they can't be merely saved and    *
  43.  * restored.)  The various indexes into the line that are used in this  *
  44.  * file only are not translated: they remain indexes into the metafied  *
  45.  * line.                                                                */
  46.  
  47. #ifdef HAVE_NIS_PLUS
  48. # include <rpcsvc/nis.h>
  49. #else
  50. # ifdef HAVE_NIS
  51. #  include    <rpc/types.h>
  52. #  include    <rpc/rpc.h>
  53. #  include    <rpcsvc/ypclnt.h>
  54. #  include    <rpcsvc/yp_prot.h>
  55.  
  56. /* This is used when getting usernames from the NIS. */
  57. typedef struct {
  58.     int len;
  59.     char *s;
  60. }
  61. dopestring;
  62. # endif
  63. #endif
  64.  
  65. #define inststr(X) inststrlen((X),1,-1)
  66.  
  67. /* Prefix and suffix for globbing, used as an optimisation. */
  68.  
  69. extern char *glob_pre, *glob_suf;
  70.  
  71. /* wb and we hold the beginning/end position of the word we are completing. */
  72.  
  73. static int wb, we;
  74.  
  75. /* offs is the cursor position within the tokenized *
  76.  * current word after removing nulargs.             */
  77.  
  78. static int offs;
  79.  
  80. /* These control the type of completion that will be done.  They are    *
  81.  * affected by the choice of ZLE command and by relevant shell options. */
  82.  
  83. static int usemenu, useglob;
  84.  
  85. /* A pointer to the current position in the menu-completion array (the one *
  86.  * that was put in the command line last).                                 */
  87.  
  88. static char **menucur;
  89.  
  90. /* The point (in the command line) where the menu-completion strings are  *
  91.  * inserted, the length of the string that was inserted last, the end     *
  92.  * position of this string in the command line and two flags: menuwe is   *
  93.  * non-zero if the cursor was at the end of the word (which means that we *
  94.  * can add suffixes, e.g. a slash for directories), and menuce is used to *
  95.  * save/restore the value of complexpect during consecutive menu          *
  96.  * completions (complexpect is used when completing after `$' or `${' and *
  97.  * says whether some characters should be treated specially, when the     *
  98.  * option autoparamkeys is set).  menuinsc is nonzero if a trailing slash *
  99.  * marking a directory is added.                                          */
  100.  
  101. static int menupos, menulen, menuend, menuwe, menuce, menuinsc;
  102.  
  103. /* The list of matches.  fmatches contains the matches we first ignore *
  104.  * because of fignore.                                                 */
  105.  
  106. static LinkList matches, fmatches;
  107.  
  108. /* The list of matches turned into an array.  This is used to sort this *
  109.  * list and when menu-completion is used (directly or via automenu).    */
  110.  
  111. static char **amatches;
  112.  
  113. /* The number of matches. */
  114.  
  115. static int nmatches;
  116.  
  117. /* !=0 if we have a valid completion list. */
  118.  
  119. static int validlist;
  120.  
  121. /* This flag is non-zero if we are completing a pattern (with globcomplete) */
  122.  
  123. static int ispattern;
  124.  
  125. /* Two patterns used when doing glob-completion.  The first one is built *
  126.  * from the whole word we are completing and the second one from that    *
  127.  * part of the word that was identified as a possible filename.          */
  128.  
  129. static Comp patcomp, filecomp;
  130.  
  131. /* We store the following prefixes/suffixes:                             *
  132.  * lpre/lsuf -- what's on the line                                       *
  133.  * rpre/rsuf -- same as lpre/lsuf, but expanded                          *
  134.  *                                                                       *
  135.  * ... and if we are completing files, too:                              *
  136.  * ppre/psuf -- the path prefix/suffix                                   *
  137.  * fpre/fsuf -- prefix/suffix of the pathname component the cursor is in *
  138.  * prpre     -- ppre in expanded form usable for opendir                 *
  139.  *                                                                       *
  140.  * The integer variables hold the lengths of lpre, lsuf, rpre, rsuf,     *
  141.  * fpre, and fsuf.  noreal is non-zero if we have rpre/rsuf.             */
  142.  
  143. static char *lpre, *lsuf;
  144. static char *rpre, *rsuf;
  145. static char *ppre, *psuf, *prpre;
  146. static char *fpre, *fsuf;
  147. static int lpl, lsl, rpl, rsl, fpl, fsl;
  148. static int noreal;
  149.  
  150. /* This is used when completing after `$' and holds the whole prefix,   *
  151.  * used in do_single() to check whether the word expands to a directory *
  152.  * name (in that case and if autoparamslash is set, we add a `/').      *
  153.  * qparampre is the same but quoted. The length of it is in qparprelen  */
  154.  
  155. static char *parampre = NULL, *qparampre = NULL;
  156. static int qparprelen;
  157.  
  158. /* This is either zero or equal to the special character the word we are *
  159.  * trying to complete starts with (e.g. Tilde or Equals).                */
  160.  
  161. static char ic;
  162.  
  163. /* These hold the minimum common prefix/suffix lengths (normal and for *
  164.  * fignore ignored).                                                   */
  165.  
  166. static int ab, ae, fab, fae;
  167.  
  168. /* This variable says what we are currently adding to the list of matches. */
  169.    
  170. static int addwhat;
  171.  
  172. /* firstm hold the first match we found, shortest contains the shortest *
  173.  * one (normal and for fignore ignored).                                */
  174.  
  175. static char *firstm, *shortest, *ffirstm, *fshortest;
  176.  
  177. /* This holds the word we are completing in quoted from. */
  178.  
  179. static char *qword;
  180.  
  181. /* This is the length of the shortest match we found (normal and for *
  182.  * fignore ignored).                                                 */
  183.  
  184. static int shortl, fshortl;
  185.  
  186. /* This is non-zero if we are doing a menu-completion and this is not the *
  187.  * first call (e.g. when automenu is set and menu-completion was entered  *
  188.  * due to this). */
  189.  
  190. static int amenu;
  191.  
  192. /* This is used by expandorcompleteprefix to save the position of the *
  193.  * inserted space (so that we can remove it later).                   */
  194.  
  195. static int remove_at = -1;
  196.  
  197. /* Find out if we have to insert a tab (instead of trying to complete). */
  198.  
  199. /**/
  200. int
  201. usetab(void)
  202. {
  203.     unsigned char *s = line + cs - 1;
  204.  
  205.     for (; s >= line && *s != '\n'; s--)
  206.     if (*s != '\t' && *s != ' ')
  207.         return 0;
  208.     return 1;
  209. }
  210.  
  211. #define COMP_COMPLETE 0
  212. #define COMP_LIST_COMPLETE 1
  213. #define COMP_SPELL 2
  214. #define COMP_EXPAND 3
  215. #define COMP_EXPAND_COMPLETE 4
  216. #define COMP_LIST_EXPAND 5
  217. #define COMP_ISEXPAND(X) ((X) >= COMP_EXPAND)
  218.  
  219. /**/
  220. void
  221. completeword(void)
  222. {
  223.     usemenu = isset(MENUCOMPLETE);
  224.     useglob = isset(GLOBCOMPLETE);
  225.     if (c == '\t' && usetab())
  226.     selfinsert();
  227.     else
  228.     docomplete(COMP_COMPLETE);
  229. }
  230.  
  231. /**/
  232. void
  233. menucomplete(void)
  234. {
  235.     usemenu = 1;
  236.     useglob = isset(GLOBCOMPLETE);
  237.     if (c == '\t' && usetab())
  238.     selfinsert();
  239.     else
  240.     docomplete(COMP_COMPLETE);
  241. }
  242.  
  243. /**/
  244. void
  245. listchoices(void)
  246. {
  247.     usemenu = isset(MENUCOMPLETE);
  248.     useglob = isset(GLOBCOMPLETE);
  249.     docomplete(COMP_LIST_COMPLETE);
  250. }
  251.  
  252. /**/
  253. void
  254. spellword(void)
  255. {
  256.     usemenu = useglob = 0;
  257.     docomplete(COMP_SPELL);
  258. }
  259.  
  260. /**/
  261. void
  262. deletecharorlist(void)
  263. {
  264.     char **mc = menucur;
  265.  
  266.     usemenu = isset(MENUCOMPLETE);
  267.     useglob = isset(GLOBCOMPLETE);
  268.     if (cs != ll)
  269.     deletechar();
  270.     else
  271.     docomplete(COMP_LIST_COMPLETE);
  272.  
  273.     menucur = mc;
  274. }
  275.  
  276. /**/
  277. void
  278. expandword(void)
  279. {
  280.     usemenu = useglob = 0;
  281.     if (c == '\t' && usetab())
  282.     selfinsert();
  283.     else
  284.     docomplete(COMP_EXPAND);
  285. }
  286.  
  287. /**/
  288. void
  289. expandorcomplete(void)
  290. {
  291.     usemenu = isset(MENUCOMPLETE);
  292.     useglob = isset(GLOBCOMPLETE);
  293.     if (c == '\t' && usetab())
  294.     selfinsert();
  295.     else
  296.     docomplete(COMP_EXPAND_COMPLETE);
  297. }
  298.  
  299. /**/
  300. void
  301. menuexpandorcomplete(void)
  302. {
  303.     usemenu = 1;
  304.     useglob = isset(GLOBCOMPLETE);
  305.     if (c == '\t' && usetab())
  306.     selfinsert();
  307.     else
  308.     docomplete(COMP_EXPAND_COMPLETE);
  309. }
  310.  
  311. /**/
  312. void
  313. listexpand(void)
  314. {
  315.     usemenu = isset(MENUCOMPLETE);
  316.     useglob = isset(GLOBCOMPLETE);
  317.     docomplete(COMP_LIST_EXPAND);
  318. }
  319.  
  320. /**/
  321. void
  322. reversemenucomplete(void)
  323. {
  324.     if (!menucmp) {
  325.     menucomplete();
  326.     return;
  327.     }
  328.     HEAPALLOC {
  329.     if (menucur == amatches)
  330.         menucur = amatches + nmatches - 1;
  331.     else
  332.         menucur--;
  333.     complexpect = menuce;
  334.     metafy_line();
  335.     do_single(*menucur);
  336.     unmetafy_line();
  337.     } LASTALLOC;
  338. }
  339.  
  340. /* Accepts the current completion and starts a new arg, *
  341.  * with the next completions. This gives you a way to   *
  342.  * accept several selections from the list of matches.  */
  343.  
  344. /**/
  345. void
  346. acceptandmenucomplete(void)
  347. {
  348.     if (!menucmp) {
  349.     feep();
  350.     return;
  351.     }
  352.     cs = menuend;
  353.     inststrlen(" ", 1, 1);
  354.     if (qparampre)
  355.     inststrlen(qparampre, 1, qparprelen);
  356.     if (lpre)
  357.     inststrlen(lpre, 1, -1);
  358.     if (lsuf)
  359.     inststrlen(lsuf, 0, -1);
  360.     menupos = cs;
  361.     menuend = cs + (lsuf ? strlen(lsuf) : 0);
  362.     menulen = 0;
  363.     menuwe = 1;
  364.     menucomplete();
  365. }
  366.  
  367. /* These are flags saying if we are completing in the command *
  368.  * position or in a redirection.                              */
  369.  
  370. static int lincmd, linredir;
  371.  
  372. /* Non-zero if the last completion done was ambiguous (used to find   *
  373.  * out if AUTOMENU should start).  More precisely, it's nonzero after *
  374.  * successfully doing any completion, unless the completion was       *
  375.  * unambiguous and did not cause the display of a completion list.    *
  376.  * From the other point of view, it's nonzero iff AUTOMENU (if set)   *
  377.  * should kick in on another completion (provided the text isn't      *
  378.  * changed in the meantime... AAAAAAAAAAUUUUGGGHH!).                  */
  379.  
  380. static int lastambig;
  381.  
  382. /* This describes some important things collected during the last *
  383.  * completion.  Its value is zero or the inclusive OR of some of  *
  384.  * the HAS_* things below.                                        */
  385.  
  386. static int haswhat;
  387.  
  388. /* We have a suffix to add (given with compctl -S). */
  389.  
  390. #define HAS_SUFFIX  1
  391.  
  392. /* We have filenames in the completion list. */
  393.  
  394. #define HAS_FILES   2
  395.  
  396. /* We have other things than files in the completion list.  If this is *
  397.  * not set but HAS_FILES is, we probably put the file type characters  *
  398.  * in the completion list (if listtypes is set) and we attempt to add  *
  399.  * a slash to completed directories.                                   */
  400.  
  401. #define HAS_MISC    4
  402.  
  403. /* This is set if we have filenames in the completion list that were *
  404.  * generated by a globcompletion pattern.                            */
  405.  
  406. #define HAS_PATHPAT 8
  407.  
  408.  
  409. /* This holds the naem of the current command (used to find the right *
  410.  * compctl).                                                          */
  411.  
  412. static char *cmdstr;
  413.  
  414.  
  415. /* Check if the given string is the name of a parameter and if this *
  416.  * parameter is one worth expanding.                                */
  417.  
  418. /**/
  419. int
  420. checkparams(char *p)
  421. {
  422.     int t0, n, l = strlen(p), e = 0;
  423.     struct hashnode *hn;
  424.  
  425.     for (t0 = paramtab->hsize - 1, n = 0; n < 2 && t0 >= 0; t0--)
  426.     for (hn = paramtab->nodes[t0]; n < 2 && hn; hn = hn->next)
  427.         if (pfxlen(p, hn->nam) == l) {
  428.         n++;
  429.         if (strlen(hn->nam) == l)
  430.             e = 1;
  431.         }
  432.     return (n == 1) ? (getsparam(p) != NULL) :
  433.     (!menucmp && e && isset(RECEXACT));
  434. }
  435.  
  436. /* Check if the given string has wildcards.  The difficulty is that we *
  437.  * have to treat things like job specifications (%...) and parameter   *
  438.  * expressions correctly.                                              */
  439.  
  440. /**/
  441. int
  442. cmphaswilds(char *str)
  443. {
  444.     if ((*str == Inbrack || *str == Outbrack) && !str[1])
  445.     return 0;
  446.  
  447.     /* If a leading % is immediately followed by ?, then don't *
  448.      * treat that ? as a wildcard.  This is so you don't have  *
  449.      * to escape job references such as %?foo.                 */
  450.     if (str[0] == '%' && str[1] ==Quest)
  451.     str += 2;
  452.  
  453.     for (; *str;) {
  454.     if (*str == String || *str == Qstring) {
  455.         /* A parameter expression. */
  456.  
  457.         if (*++str == Inbrace)
  458.         skipparens(Inbrace, Outbrace, &str);
  459.         else if (*str == String || *str == Qstring)
  460.         str++;
  461.         else {
  462.         /* Skip all the things a parameter expression might start *
  463.          * with (before we come to the parameter name).           */
  464.         for (; *str; str++)
  465.             if (*str != '^' && *str != Hat &&
  466.             *str != '=' && *str != Equals &&
  467.             *str != '~' && *str != Tilde)
  468.             break;
  469.         if (*str == '#' || *str == Pound)
  470.             str++;
  471.         /* Star and Quest are parameter names here, not wildcards */
  472.         if (*str == Star || *str == Quest)
  473.             str++;
  474.         }
  475.     } else {
  476.         /* Not a parameter expression so we check for wildcards */
  477.         if (*str == Pound || *str == Hat || *str == Star ||
  478.         *str == Bar || *str == Quest ||
  479.         !skipparens(Inbrack, Outbrack, &str) ||
  480.         !skipparens(Inang,   Outang,   &str) ||
  481.         (!isset(IGNOREBRACES) &&
  482.          !skipparens(Inbrace, Outbrace, &str)) ||
  483.         (*str == Inpar && str[1] == ':' &&
  484.          !skipparens(Inpar, Outpar, &str)))
  485.         return 1;
  486.         if (*str)
  487.         str++;
  488.     }
  489.     }
  490.     return 0;
  491. }
  492.  
  493. /* The main entry point for completion. */
  494.  
  495. /**/
  496. void
  497. docomplete(int lst)
  498. {
  499.     char *s, *ol;
  500.     int olst = lst, chl = 0, ne = noerrs, ocs;
  501.  
  502.     /* If we are doing a menu-completion... */
  503.  
  504.     if (menucmp && lst != COMP_LIST_EXPAND) {
  505.     do_menucmp(lst);
  506.     return;
  507.     }
  508.     
  509.     /* Check if we have to start a menu-completion (via automenu). */
  510.  
  511.     if ((amenu = (isset(AUTOMENU) &&
  512.                (lastcmd & ZLE_MENUCMP) &&
  513.                lastambig)))
  514.     usemenu = 1;
  515.  
  516.     /* Expand history references before starting completion.  If anything *
  517.      * changed, do no more.                                               */
  518.  
  519.     if (doexpandhist())
  520.     return;
  521.  
  522.     metafy_line();
  523.  
  524.     ocs = cs;
  525.     if (!isfirstln && chline != NULL) {
  526.     /* If we are completing in a multi-line buffer (which was not  *
  527.      * taken from the history), we have to prepend the stuff saved *
  528.      * in chline to the contents of line.                          */
  529.  
  530.     ol = dupstring((char *)line);
  531.     /* Make sure that chline is zero-terminated. */
  532.     *hptr = '\0';
  533.     cs = 0;
  534.     inststr(chline);
  535.     chl = cs;
  536.     cs += ocs;
  537.     } else
  538.     ol = NULL;
  539.     inwhat = IN_NOTHING;
  540.     qword = NULL;
  541.     /* Get the word to complete. */
  542.     noerrs = 1;
  543.     s = get_comp_string();
  544.     DPUTS(wb < 0 || cs < wb || cs > we,
  545.       "BUG: 0 <= wb <= cs <= we is not true!");
  546.     noerrs = ne;
  547.     /* For vi mode, reset the start-of-insertion pointer to the beginning *
  548.      * of the word being completed, if it is currently later.  Vi itself  *
  549.      * would never change the pointer in the middle of an insertion, but  *
  550.      * then vi doesn't have completion.  More to the point, this is only  *
  551.      * an emulation.                                                      */
  552.     if (viinsbegin > ztrsub((char *) line + wb, (char *) line))
  553.     viinsbegin = ztrsub((char *) line + wb, (char *) line);
  554.     /* If we added chline to the line buffer, reset the original contents. */
  555.     if (ol) {
  556.     cs -= chl;
  557.     wb -= chl;
  558.     we -= chl;
  559.     if (wb < 0) {
  560.         strcpy((char *) line, ol);
  561.         ll = strlen((char *) line);
  562.         cs = ocs;
  563.         unmetafy_line();
  564.         feep();
  565.         return;
  566.     }
  567.     ocs = cs;
  568.     cs = 0;
  569.     foredel(chl);
  570.     cs = ocs;
  571.     }
  572.     freeheap();
  573.     /* Save the lexer state, in case the completion code uses the lexer *
  574.      * somewhere (e.g. when processing a compctl -s flag).              */
  575.     lexsave();
  576.     if (inwhat == IN_ENV)
  577.     lincmd = 0;
  578.     if (s) {
  579.     if (lst == COMP_EXPAND_COMPLETE) {
  580.         /* Check if we have to do expansion or completion. */
  581.         char *q = s;
  582.  
  583.         if (*q == Equals) {
  584.         /* The word starts with `=', see if we can expand it. */
  585.         q = s + 1;
  586.         if (cmdnamtab->getnode(cmdnamtab, q) || hashcmd(q, pathchecked))
  587.             if (isset(RECEXACT))
  588.             lst = COMP_EXPAND;
  589.             else {
  590.             int t0, n = 0;
  591.             char *fc;
  592.             struct hashnode *hn;
  593.  
  594.             for (t0 = cmdnamtab->hsize - 1; t0 >= 0; t0--)
  595.                 for (hn = cmdnamtab->nodes[t0]; hn;
  596.                  hn = hn->next) {
  597.                 if (strpfx(q, hn->nam) && (fc = findcmd(hn->nam))) {
  598.                     zsfree(fc);
  599.                     n++;
  600.                 }
  601.                 if (n == 2)
  602.                     break;
  603.                 }
  604.  
  605.             if (n == 1)
  606.                 lst = COMP_EXPAND;
  607.             }
  608.         }
  609.         if (lst == COMP_EXPAND_COMPLETE)
  610.         do {
  611.             /* check if there is a parameter expresiion. */
  612.             for (; *q && *q != String; q++);
  613.             if (*q == String && q[1] != Inpar && q[1] != Inbrack) {
  614.             if (*++q == Inbrace) {
  615.                 if (! skipparens(Inbrace, Outbrace, &q) &&
  616.                 q == s + cs - wb)
  617.                 lst = COMP_EXPAND;
  618.             } else {
  619.                 char *t, sav, sav2;
  620.  
  621.                 /* Skip the things parameter expressions might *
  622.                  * start with (the things before the parameter *
  623.                  * name).                                      */
  624.                 for (; *q; q++)
  625.                 if (*q != '^' && *q != Hat &&
  626.                     *q != '=' && *q != Equals &&
  627.                     *q != '~' && *q != Tilde)
  628.                     break;
  629.                 if ((*q == '#' || *q == Pound || *q == '+') &&
  630.                 q[1] != String)
  631.                 q++;
  632.  
  633.                 sav2 = *(t = q);
  634.                 if (*q == Quest || *q == Star || *q == String ||
  635.                 *q == Qstring)
  636.                 *q = ztokens[*q - Pound], ++q;
  637.                 else if (*q == '?' || *q == '*' || *q == '$' ||
  638.                      *q == '-' || *q == '!' || *q == '@')
  639.                 q++;
  640.                 else if (idigit(*q))
  641.                 do q++; while (idigit(*q));
  642.                 else
  643.                 while (iident(*q))
  644.                     q++;
  645.                 sav = *q;
  646.                 *q = '\0';
  647.                 if (cs - wb == q - s &&
  648.                 (idigit(sav2) || checkparams(t)))
  649.                 lst = COMP_EXPAND;
  650.                 *q = sav;
  651.                 *t = sav2;
  652.             }
  653.             if (lst != COMP_EXPAND)
  654.                 lst = COMP_COMPLETE;
  655.             } else
  656.             break;
  657.         } while (q < s + cs - wb);
  658.         if (lst == COMP_EXPAND_COMPLETE) {
  659.         /* If it is still not clear if we should use expansion or   *
  660.          * completion and there is a `$' or a backtick in the word, *
  661.          * than do expansion.                                       */
  662.         for (q = s; *q; q++)
  663.             if (*q == Tick || *q == Qtick ||
  664.             *q == String || *q == Qstring)
  665.             break;
  666.         lst = *q ? COMP_EXPAND : COMP_COMPLETE;
  667.         }
  668.         /* And do expansion if there are wildcards and globcomplete is *
  669.          * not used.                                                   */
  670.         if (unset(GLOBCOMPLETE) && cmphaswilds(s))
  671.         lst = COMP_EXPAND;
  672.     }
  673.     if (lincmd && (inwhat == IN_NOTHING))
  674.         inwhat = IN_CMD;
  675.  
  676.     if (lst == COMP_SPELL) {
  677.         char **x = &s;
  678.         char *q = s;
  679.  
  680.         for (; *q; q++)
  681.         if (INULL(*q))
  682.             *q = Nularg;
  683.         untokenize(s);
  684.         cs = wb;
  685.         foredel(we - wb);
  686.         /* call the real spell checker, ash@aaii.oz.zu */
  687.         spckword(x, 0, lincmd, 0);
  688.         inststr(*x);
  689.     } else if (COMP_ISEXPAND(lst)) {
  690.         /* Do expansion. */
  691.         char *ol = (olst == COMP_EXPAND_COMPLETE) ?
  692.         dupstring((char *)line) : (char *)line;
  693.         int ocs = cs, ne = noerrs;
  694.  
  695.         noerrs = 1;
  696.         doexpansion(s, lst, olst, lincmd);
  697.         lastambig = 0;
  698.         noerrs = ne;
  699.  
  700.         /* If expandorcomplete was invoked and the expansion didn't *
  701.          * change the command line, do completion.                  */
  702.         if (olst == COMP_EXPAND_COMPLETE &&
  703.         !strcmp(ol, (char *)line)) {
  704.         char *p;
  705.  
  706.         cs = ocs;
  707.         errflag = 0;
  708.  
  709.         p = s;
  710.         if (*p == Tilde || *p == Equals)
  711.             p++;
  712.         for (; *p; p++)
  713.             if (itok(*p))
  714.             if (*p != String && *p != Qstring)
  715.                 *p = ztokens[*p - Pound];
  716.             else if (p[1] == Inbrace)
  717.                 p++, skipparens(Inbrace, Outbrace, &p);
  718.         docompletion(s, lst, lincmd);
  719.         }
  720.     } else
  721.         /* Just do completion. */
  722.         docompletion(s, lst, lincmd);
  723.     zsfree(s);
  724.     }
  725.     /* Reset the lexer state, pop the heap. */
  726.     lexrestore();
  727.     popheap();
  728.     zsfree(qword);
  729.     menuce = complexpect;
  730.     unmetafy_line();
  731. }
  732.  
  733. /* Do completion, given that we are in the middle of a menu completion.  We *
  734.  * don't need to generate a list of matches, because that's already been    *
  735.  * done by previous commands.  We will either list the completions, or      *
  736.  * insert the next completion.                                              */
  737.  
  738. /**/
  739. void
  740. do_menucmp(int lst)
  741. {
  742.     /* Just list the matches if the list was requested. */
  743.     if (lst == COMP_LIST_COMPLETE) {
  744.     showinglist = -2;
  745.     return;
  746.     }
  747.     /* Otherwise go to the next match in the array... */
  748.     HEAPALLOC {
  749.     if (!*++menucur)
  750.         menucur = amatches;
  751.     complexpect = menuce;
  752.     /* ... and insert it into the command line. */
  753.     metafy_line();
  754.     do_single(*menucur);
  755.     unmetafy_line();
  756.     } LASTALLOC;
  757. }
  758.  
  759. /* 1 if x added to complete in a blank between words */
  760. int addedx;
  761.  
  762. /* 1 if we are completing in a string */
  763. int instring;
  764.  
  765. /* This function inserts an `x' in the command line at the cursor position. *
  766.  *                                                                          *
  767.  * Oh, you want to know why?  Well, if completion is tried somewhere on an  *
  768.  * empty part of the command line, the lexer code would normally not be     *
  769.  * able to give us the `word' we want to complete, since there is no word.  *
  770.  * But we need to call the lexer to find out where we are (and for which    *
  771.  * command we are completing and such things).  So we temporarily add a `x' *
  772.  * (any character without special meaning would do the job) at the cursor   *
  773.  * position, than the lexer gives us the word `x' and its beginning and end *
  774.  * positions and we can remove the `x'.                                     */
  775.  
  776. /**/
  777. void
  778. addx(char **ptmp)
  779. {
  780.     if (!line[cs] || line[cs] == '\n' ||
  781.     (iblank(line[cs]) && (!cs || line[cs-1] != '\\')) ||
  782.     line[cs] == ')' || line[cs] == '`') {
  783.     *ptmp = (char *)line;
  784.     line = (unsigned char *)halloc(strlen((char *)line) + 3);
  785.     memcpy(line, *ptmp, cs);
  786.     line[cs] = 'x';
  787.     strcpy((char *)line + cs + 1, (*ptmp) + cs);
  788.     addedx = 1;
  789.     } else {
  790.     addedx = 0;
  791.     *ptmp = NULL;
  792.     }
  793. }
  794.  
  795. /* Like dupstring, but add an extra space at the end of the string. */
  796.  
  797. /**/
  798. char *
  799. dupstrspace(const char *str)
  800. {
  801.     int len = strlen((char *)str);
  802.     char *t = (char *)ncalloc(len + 2);
  803.     strcpy(t, str);
  804.     strcpy(t+len, " ");
  805.     return t;
  806. }
  807.  
  808. /* These functions metafy and unmetafy the ZLE buffer, as described at the *
  809.  * top of this file.  Note that ll and cs are translated.  They *must* be  *
  810.  * called in matching pairs, around all the expansion/completion code.     *
  811.  * Currently, there are four pairs: in history expansion, in the main      *
  812.  * completion function, and one in each of the middle-of-menu-completion   *
  813.  * functions (there's one for each direction).                             */
  814.  
  815. /**/
  816. void
  817. metafy_line(void)
  818. {
  819.     int len = ll;
  820.     char *s;
  821.  
  822.     for (s = (char *) line; s < (char *) line + ll;)
  823.     if (imeta(*s++))
  824.         len++;
  825.     sizeline(len);
  826.     (void) metafy((char *) line, ll, META_NOALLOC);
  827.     ll = len;
  828.     cs = metalen((char *) line, cs);
  829. }
  830.  
  831. /**/
  832. void
  833. unmetafy_line(void)
  834. {
  835.     cs = ztrsub((char *) line + cs, (char *) line);
  836.     (void) unmetafy((char *) line, &ll);
  837. }
  838.  
  839. /* Lasciate ogni speranza.                                                  *
  840.  * This function is a nightmare.  It works, but I'm sure that nobody really *
  841.  * understands why.  The problem is: to make it cleaner we would need       *
  842.  * changes in the lexer code (and then in the parser, and then...).         */
  843.  
  844. /**/
  845. char *
  846. get_comp_string(void)
  847. {
  848.     int t0, tt0, i, j, k, cp, rd, sl, ocs;
  849.     char *s = NULL, *linptr, *tmp, *p, *tt = NULL, *q = NULL;
  850.  
  851.     /* This global flag is used to signal the lexer code if it should *
  852.      * expand aliases or not.                                         */
  853.     noaliases = isset(COMPLETEALIASES);
  854.  
  855.     instring = 0;
  856.  
  857.     /* Find out if we are somewhere in a `string', i.e. inside '...', *
  858.      * "...", `...`, or ((...)).                                      */
  859.  
  860.     for (i = j = k = 0, q = p = (char *)line; p < (char *)line + cs; p++)
  861.     if (*p == '`' && !(k & 1))
  862.         i++, q = p;
  863.     else if (*p == '\"' && !(k & 1) && !(i & 1))
  864.         j++;
  865.     else if (*p == '\'' && !(j & 1))
  866.         k++;
  867.     else if (*p == '\\' && p[1] && !(k & 1))
  868.         p++;
  869.     if ((i & 1) || (j & 1) || (k & 1)) {
  870.     /* Yes, we are in a string. */
  871.     instring = (j & 1) ? 2 : (k & 1);
  872.     /* Now add the `x', see above. */
  873.     addx(&tmp);
  874.     if (!addedx) {
  875.         /* If no `x' was added, set the tmp variable anyway. */
  876.         tmp = (char *)line;
  877.         if (i & 1) {
  878.         line = (unsigned char *)dupstring((char *)line);
  879.         strcpy((char *)line, (char *)tmp);
  880.         } else
  881.         line = (unsigned char *)dupstring((char *)line);
  882.     }
  883.     /* Now remove the quotes.                                   *
  884.      * What??  Why that??  Well, we want to be able to complete *
  885.      * inside strings.  The lexer code gives us no help here,   *
  886.      * so we have to cheat.  We remove the quotes, the lexer    *
  887.      * will than treat the words in the strings normally and we *
  888.      * can complete them.                                       *
  889.      * This is completely the wrong thing to do, but it's       *
  890.      * occasionally useful, and we can't handle quotes properly *
  891.      * yet anyway.                                              */
  892.     for (p = (char *)line; *p; p++)
  893.         if (*p == '"' || *p == '\'')
  894.         *p = ' ';
  895.     } else
  896.     /* We are not in a string, add the `x' */
  897.     addx(&tmp);
  898.     linptr = (char *)line;
  899.     pushheap();
  900.     HEAPALLOC {
  901.       start:
  902.     inwhat = IN_NOTHING;
  903.     /* Now set up the lexer and start it. */
  904.     parbegin = parend = -1;
  905.     lincmd = incmdpos;
  906.     linredir = inredir;
  907.     zsfree(cmdstr);
  908.     cmdstr = NULL;
  909.     zleparse = 1;
  910.     clwpos = -1;
  911.     lexsave();
  912.     inpush(dupstrspace((char *) linptr), 0);
  913.     strinbeg();
  914.     stophist = 2;
  915.     i = tt0 = cp = rd = 0;
  916.  
  917.     /* This loop is possibly the wrong way to do this.  It goes through *
  918.      * the previously massaged command line using the lexer.  It stores *
  919.      * each token in each command (commands being regarded, roughly, as *
  920.      * being separated by tokens | & &! |& || &&).  The loop stops when *
  921.      * the end of the command containing the cursor is reached.  It's a *
  922.      * simple way to do things, but suffers from an inability to        *
  923.      * distinguish actual command arguments from, for example,          *
  924.      * filenames in redirections.  (But note that code elsewhere checks *
  925.      * if we are completing *in* a redirection.)  The only way to fix   *
  926.      * this would be to pass the command line through the parser too,   *
  927.      * and get the arguments that way.  Maybe in 3.1...                 */
  928.     do {
  929.         lincmd = incmdpos;
  930.         linredir = inredir;
  931.         /* Get the next token. */
  932.         ctxtlex();
  933.  
  934.         /* We reached the end. */
  935.         if (tok == ENDINPUT)
  936.         break;
  937.         if (tok == BAR    || tok == AMPER     ||
  938.         tok == BARAMP || tok == AMPERBANG ||
  939.         ((tok == DBAR || tok == DAMPER) && !incond)) {
  940.         /* This is one of the things that separate commands.  If we  *
  941.          * already have the things we need (e.g. the token strings), *
  942.          * leave the loop.                                           */
  943.         if (tt)
  944.             break;
  945.         /* Otherwise reset the variables we are collecting data in. */
  946.         i = tt0 = cp = rd = 0;
  947.         }
  948.         if (lincmd && tok == STRING) {
  949.         /* The lexer says, this token is in command position, so *
  950.          * store the token string (to find the right compctl).   */
  951.         zsfree(cmdstr);
  952.         cmdstr = ztrdup(tokstr);
  953.         i = 0;
  954.         }
  955.         if (!zleparse && !tt0) {
  956.         /* This is done when the lexer reached the word the cursor is on. */
  957.         tt = tokstr ? dupstring(tokstr) : NULL;
  958.         /* If we added a `x', remove it. */
  959.         if (addedx && tt)
  960.             chuck(tt + cs - wb - 1);
  961.         tt0 = tok;
  962.         /* Store the number of this word. */
  963.         clwpos = i;
  964.         cp = lincmd;
  965.         rd = linredir;
  966.         if (inwhat == IN_NOTHING && incond)
  967.             inwhat = IN_COND;
  968.         }
  969.         if (!tokstr)
  970.         continue;
  971.         /* We need to store the token strings of all words (for some of *
  972.          * the more complicated compctl -x things).  They are stored in *
  973.          * the clwords array.  Make this array big enough.              */
  974.         if (i + 1 == clwsize) {
  975.         int n;
  976.         clwords = (char **)realloc(clwords,
  977.                        (clwsize *= 2) * sizeof(char *));
  978.         for(n = clwsize; --n > i; )
  979.             clwords[n] = NULL;
  980.         }
  981.         zsfree(clwords[i]);
  982.         /* And store the current token string. */
  983.         clwords[i] = ztrdup(tokstr);
  984.         sl = strlen(tokstr);
  985.         /* Sometimes the lexer gives us token strings ending with *
  986.          * spaces we delete the spaces.                           */
  987.         while (sl && clwords[i][sl - 1] == ' ' &&
  988.            (sl < 2 || (clwords[i][sl - 2] != Bnull &&
  989.                    clwords[i][sl - 2] != Meta)))
  990.         clwords[i][--sl] = '\0';
  991.         /* If this is the word the cursor is in and we added a `x', *
  992.          * remove it.                                               */
  993.         if (clwpos == i++ && addedx)
  994.         chuck(&clwords[i - 1][((cs - wb - 1) >= sl) ?
  995.                      (sl - 1) : (cs - wb - 1)]);
  996.     } while (tok != LEXERR && tok != ENDINPUT &&
  997.          (tok != SEPER || (zleparse && !tt0)));
  998.     /* Calculate the number of words stored in the clwords array. */
  999.     clwnum = (tt || !i) ? i : i - 1;
  1000.     zsfree(clwords[clwnum]);
  1001.     clwords[clwnum] = NULL;
  1002.     t0 = tt0;
  1003.     lincmd = cp;
  1004.     linredir = rd;
  1005.     strinend();
  1006.     inpop();
  1007.     errflag = zleparse = 0;
  1008.     if (addedx)
  1009.         wb++;
  1010.     if (parbegin != -1) {
  1011.         /* We are in command or process substitution */
  1012.         if (parend >= 0 && !tmp)
  1013.         line = (unsigned char *) dupstring(tmp = (char *)line);
  1014.         linptr = (char *) line + ll + addedx - parbegin + 1;
  1015.         if (parend >= 0) {
  1016.         ll -= parend;
  1017.         line[ll + addedx] = '\0';
  1018.         }
  1019.         lexrestore();
  1020.         goto start;
  1021.     }
  1022.  
  1023.     if (inwhat == IN_MATH)
  1024.         s = NULL;
  1025.     else if (!t0 || t0 == ENDINPUT) {
  1026.         /* There was no word (empty line). */
  1027.         s = ztrdup("");
  1028.         we = wb = cs;
  1029.         clwpos = clwnum;
  1030.         t0 = STRING;
  1031.     } else if (t0 == STRING) {
  1032.         /* We found a simple string. */
  1033.         s = ztrdup(clwords[clwpos]);
  1034.     } else if (t0 == ENVSTRING) {
  1035.         /* The cursor was inside a parameter assignment. */
  1036.         for (s = tt; iident(*s); s++);
  1037.         if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + cs - wb)
  1038.         s = NULL, inwhat = IN_MATH;
  1039.         else if (*s == '=') {
  1040.         s++;
  1041.         wb += s - tt;
  1042.         t0 = STRING;
  1043.         s = ztrdup(s);
  1044.         inwhat = IN_ENV;
  1045.         }
  1046.         lincmd = 1;
  1047.     }
  1048.     if (we > ll)
  1049.         we = ll;
  1050.     tt = (char *)line;
  1051.     if (tmp) {
  1052.         line = (unsigned char *)tmp;
  1053.         ll = strlen((char *)line);
  1054.     }
  1055.     if (t0 != STRING && inwhat != IN_MATH) {
  1056.         if (tmp) {
  1057.         tmp = NULL;
  1058.         linptr = (char *)line;
  1059.         lexrestore();
  1060.         goto start;
  1061.         }
  1062.         feep();
  1063.         noaliases = 0;
  1064.         lexrestore();
  1065.         LASTALLOC_RETURN NULL;
  1066.     }
  1067.  
  1068.     noaliases = 0;
  1069.  
  1070.     /* Check if we are in an array subscript.  We simply assume that  *
  1071.      * we are in a subscript if we are in brackets.  Correct solution *
  1072.      * is very difficult.  This is quite close, but gets things like  *
  1073.      * foo[_ wrong (note no $).  If we are in a subscript, treat it   *
  1074.      * as being in math.                                              */
  1075.     if (inwhat != IN_MATH) {
  1076.         int i = 0;
  1077.         for (tt = s; ++tt < s + cs - wb;)
  1078.         if (*tt == Inbrack)
  1079.             i++;
  1080.         else if (i && *tt == Outbrack)
  1081.             i--;
  1082.         if (i)
  1083.         inwhat = IN_MATH;
  1084.     }
  1085.     if (inwhat == IN_MATH) {
  1086.         /* In mathematical expression, we complete parameter names (even *
  1087.          * if they don't have a `$' in front of them).  So we have to    *
  1088.          * find that name.                                               */
  1089.         for (we = cs; iident(line[we]); we++);
  1090.         for (wb = cs; --wb >= 0 && iident(line[wb]););
  1091.         wb++;
  1092.         zsfree(s);
  1093.         s = zalloc(we - wb + 1);
  1094.         strncpy(s, (char *) line + wb, we - wb);
  1095.         s[we - wb] = '\0';
  1096.     }
  1097.     /* This variable will hold the current word in quoted form. */
  1098.     qword = ztrdup(s);
  1099.     /* While building the quoted form, we also clean up the command line. */
  1100.     offs = cs - wb;
  1101.     for (p = s, tt = qword, i = wb; *p; p++, tt++, i++)
  1102.         if (INULL(*p)) {
  1103.         if (i < cs)
  1104.             offs--;
  1105.         if (p[1] || *p != Bnull) {
  1106.             if (*p == Bnull) {
  1107.             *tt = '\\';
  1108.             if (cs == i + 1)
  1109.                 cs++, offs++;
  1110.             } else {
  1111.             ocs = cs;
  1112.             cs = i;
  1113.             foredel(1);
  1114.             chuck(tt--);
  1115.             if ((cs = ocs) >= i--)
  1116.                 cs--;
  1117.             we--;
  1118.             }
  1119.         } else {
  1120.             ocs = cs;
  1121.             *tt = '\0';
  1122.             cs = we;
  1123.             backdel(1);
  1124.             if (ocs == we)
  1125.             cs = we - 1;
  1126.             else
  1127.             cs = ocs;
  1128.             we--;
  1129.         }
  1130.         chuck(p--);
  1131.         }
  1132.     } LASTALLOC;
  1133.     lexrestore();
  1134.  
  1135.     return (char *)s;
  1136. }
  1137.  
  1138. /* Expand the current word. */
  1139.  
  1140. /**/
  1141. void
  1142. doexpansion(char *s, int lst, int olst, int explincmd)
  1143. {
  1144.     LinkList vl;
  1145.     char *ss;
  1146.  
  1147.     DPUTS(useheap, "BUG: useheap in doexpansion()");
  1148.     HEAPALLOC {
  1149.     pushheap();
  1150.     vl = newlinklist();
  1151.     ss = dupstring(s);
  1152.     addlinknode(vl, ss);
  1153.     prefork(vl, 0);
  1154.     if (errflag)
  1155.         goto end;
  1156.     if ((lst == COMP_LIST_EXPAND) || (lst == COMP_EXPAND)) {
  1157.         int ng = opts[NULLGLOB];
  1158.  
  1159.         opts[NULLGLOB] = 1;
  1160.         globlist(vl);
  1161.         opts[NULLGLOB] = ng;
  1162.     }
  1163.     if (errflag)
  1164.         goto end;
  1165.     if (empty(vl) || !*(char *)peekfirst(vl)) {
  1166.         if (!noerrs)
  1167.         feep();
  1168.         goto end;
  1169.     }
  1170.     if (peekfirst(vl) == (void *) ss ||
  1171.         (olst == COMP_EXPAND_COMPLETE &&
  1172.          !nextnode(firstnode(vl)) && *s == Tilde &&
  1173.          (ss = dupstring(s), filesubstr(&ss, 0)) &&
  1174.          !strcmp(ss, (char *)peekfirst(vl)))) {
  1175.         /* If expansion didn't change the word, try completion if *
  1176.          * expandorcomplete was called, otherwise, just beep.     */
  1177.         if (lst == COMP_EXPAND_COMPLETE)
  1178.         docompletion(s, COMP_COMPLETE, explincmd);
  1179.         else
  1180.         feep();
  1181.         goto end;
  1182.     }
  1183.     if (lst == COMP_LIST_EXPAND) {
  1184.         /* Only the list of expansions was requested. */
  1185.         listlist(vl);
  1186.         goto end;
  1187.     }
  1188.     /* Remove the current word and put the expansions there. */
  1189.     cs = wb;
  1190.     foredel(we - wb);
  1191.     while ((ss = (char *)ugetnode(vl))) {
  1192.         untokenize(ss);
  1193.         ss = quotename(ss, NULL, NULL, NULL);
  1194.         inststr(ss);
  1195. #if 0
  1196.         if (nonempty(vl)) {
  1197.         spaceinline(1);
  1198.         line[cs++] = ' ';
  1199.         }
  1200. #endif
  1201.         if (olst != COMP_EXPAND_COMPLETE || nonempty(vl) ||
  1202.         (cs && line[cs-1] != '/')) {
  1203.         spaceinline(1);
  1204.         line[cs++] = ' ';
  1205.         }
  1206.     }
  1207.       end:
  1208.     popheap();
  1209.     } LASTALLOC;
  1210. }
  1211.  
  1212. /* This is called from the lexer to give us word positions. */
  1213.  
  1214. /**/
  1215. void
  1216. gotword(void)
  1217. {
  1218.     we = ll + 1 - inbufct;
  1219.     if (cs <= we) {
  1220.     wb = ll - wordbeg;
  1221.     zleparse = 0;
  1222.     }
  1223. }
  1224.  
  1225. /* Insert the given string into the command line.  If move is non-zero, *
  1226.  * the cursor position is changed and len is the length of the string   *
  1227.  * to insert (if it is -1, the length is calculated here).              */
  1228.  
  1229. /**/
  1230. void
  1231. inststrlen(char *str, int move, int len)
  1232. {
  1233.     if (!len)
  1234.     return;
  1235.     if (len == -1)
  1236.     len = strlen(str);
  1237.     spaceinline(len);
  1238.     strncpy((char *)(line + cs), str, len);
  1239.     if (remove_at >= cs)
  1240.         remove_at += len;
  1241.     if (move)
  1242.     cs += len;
  1243. }
  1244.  
  1245. /* Quote the string s and return the result.  If e is non-zero, it the    *
  1246.  * pointer it points to may point to aposition in s and in e the position *
  1247.  * of the corresponding character in the quoted string is returned.  Like *
  1248.  * e, te may point to a position in the string and pl is used to return   *
  1249.  * the position of the character pointed to by te in the quoted string.   *
  1250.  * The string is metafied and may contain tokens.                         */
  1251.  
  1252. /**/
  1253. char *
  1254. quotename(char *s, char **e, char *te, int *pl)
  1255. {
  1256.     char *tt, *v, *u, buf[PATH_MAX * 2];
  1257.     int sf = 0;
  1258.  
  1259.     tt = v = buf;
  1260.     u = s;
  1261.     for (; *u; u++) {
  1262.     if (e && *e == u)
  1263.         *e = v, sf |= 1;
  1264.     if (te == u)
  1265.         *pl = v - tt, sf |= 2;
  1266.     if (ispecial(*u) &&
  1267.         (!instring || (!isset(NOBANGHIST) &&
  1268.                *u == (char)bangchar) ||
  1269.          (instring == 2 &&
  1270.           (*u == '$' || *u == '`' || *u == '\"')) ||
  1271.          (instring == 1 && *u == '\'')))
  1272.         if (*u == '\n' || (instring == 1 && *u == '\'')) {
  1273.         if (unset(RCQUOTES)) {
  1274.             *v++ = '\'';
  1275.             if (*u == '\'')
  1276.             *v++ = '\\';
  1277.             *v++ = *u;
  1278.             *v++ = '\'';
  1279.         } else if (*u == '\n')
  1280.             *v++ = '"', *v++ = '\n', *v++ = '"';
  1281.         else
  1282.             *v++ = '\'', *v++ = '\'';
  1283.         continue;
  1284.         } else
  1285.         *v++ = '\\';
  1286.     if(*u == Meta)
  1287.         *v++ = *u++;
  1288.     *v++ = *u;
  1289.     }
  1290.     *v = '\0';
  1291.     if (strcmp(buf, s))
  1292.     tt = dupstring(buf);
  1293.     else
  1294.     tt = s;
  1295.     v += tt - buf;
  1296.     if (e && (sf & 1))
  1297.     *e += tt - buf;
  1298.  
  1299.     if (e && *e == u)
  1300.     *e = v;
  1301.     if (te == u)
  1302.     *pl = v - tt;
  1303.  
  1304.     return tt;
  1305. }
  1306.  
  1307. /* This adds a match to the list of matches.  The string to add is given   *
  1308.  * in s, the type of match is given in the global variable addwhat and     *
  1309.  * the parameter t (if not NULL) is a pointer to a hash node node which    *
  1310.  * may be used to give other information to this function.                 *
  1311.  *                                                                         *
  1312.  * addwhat contains either one of the special values (negative, see below) *
  1313.  * or the inclusive OR of some of the CC_* flags used for compctls.        */
  1314.  
  1315. /**/
  1316. void
  1317. addmatch(char *s, char *t)
  1318. {
  1319.     int test = 0, sl = strlen(s), pl = rpl, cc = 0, *bp, *ep, *sp;
  1320.     char *e = NULL, *tt, *te, *fc, **fm;
  1321.     Comp cp = patcomp;
  1322.     HashNode hn;
  1323.     Param pm;
  1324.     LinkList l = matches;
  1325.  
  1326. /*
  1327.  * addwhat: -5 is for files,
  1328.  *          -6 is for glob expansions,
  1329.  *          -8 is for executable files (e.g. command paths),
  1330.  *          -7 is for command names (from cmdnamtab)
  1331.  *          -3 is for executable command names.
  1332.  *          -1 is for other file specifications
  1333.  *          (things with `~' of `=' at the beginning, ...).
  1334.  */
  1335.  
  1336.     /* Just to make the code cleaner */
  1337.     hn = (HashNode) t;
  1338.     pm = (Param) t;
  1339.  
  1340.     if (!addwhat) {
  1341.     test = 1;
  1342.     } else if (addwhat == -1 || addwhat == -5 || addwhat == -6 ||
  1343.            addwhat == CC_FILES || addwhat == -7 || addwhat == -8) {
  1344.     if (sl < fpl + fsl)
  1345.         return;
  1346.  
  1347.     if ((addwhat == CC_FILES ||
  1348.          addwhat == -5) && !*psuf && !*fsuf) {
  1349.         /* If this is a filename, do the fignore check. */
  1350.         char **pt = fignore;
  1351.         int filell;
  1352.  
  1353.         for (test = 1; test && *pt; pt++)
  1354.         if ((filell = strlen(*pt)) < sl
  1355.             && !strcmp(*pt, s + sl - filell))
  1356.             test = 0;
  1357.  
  1358.         if (!test)
  1359.         l = fmatches;
  1360.     }
  1361.     pl = fpl;
  1362.     if (addwhat == -5 || addwhat == -8) {
  1363.         test = 1;
  1364.         cp = filecomp;
  1365.         cc = cp || ispattern;
  1366.         e = s + sl - fsl;
  1367.     } else {
  1368.         if ((cp = filecomp)) {
  1369.         if ((test = domatch(s, filecomp, 0)))
  1370.             cc = 1;
  1371.         } else {
  1372.         e = s + sl - fsl;
  1373.         if ((test = !strncmp(s, fpre, fpl)))
  1374.             test = !strcmp(e, fsuf);
  1375.         if (ispattern)
  1376.             cc = 1;
  1377.         }
  1378.     }
  1379.     if (test) {
  1380.         fc = NULL;
  1381.         if (addwhat == -7 && !(fc = findcmd(s)))
  1382.         return;
  1383.         if (fc)
  1384.         zsfree(fc);
  1385.         haswhat |= HAS_FILES;
  1386.  
  1387.         if (addwhat == CC_FILES || addwhat == -6 ||
  1388.         addwhat == -5 || addwhat == -8) {
  1389.         te = s + pl;
  1390.         s = quotename(s, &e, te, &pl);
  1391.         sl = strlen(s);
  1392.         } else if (!cc) {
  1393.         s = dupstring(t = s);
  1394.         e += s - t;
  1395.         }
  1396.         if (cc) {
  1397.         tt = (char *)halloc(strlen(ppre) + strlen(psuf) + sl + 1);
  1398.         strcpy(tt, ppre);
  1399.         strcat(tt, s);
  1400.         strcat(tt, psuf);
  1401.         untokenize(s = tt);
  1402.         }
  1403.     }
  1404.     } else if (addwhat == CC_QUOTEFLAG || addwhat == -2 ||
  1405.           (addwhat == -3 && !(hn->flags & DISABLED)) ||
  1406.           (addwhat == -4 && (PM_TYPE(pm->flags) == PM_SCALAR) &&
  1407.         (tt = pm->gets.cfn(pm)) && *tt == '/') ||
  1408.            (addwhat > 0 &&
  1409.         (((addwhat & CC_ARRAYS)    &&  (hn->flags & PM_ARRAY))    ||
  1410.          ((addwhat & CC_INTVARS)   &&  (hn->flags & PM_INTEGER))  ||
  1411.          ((addwhat & CC_ENVVARS)   &&  (hn->flags & PM_EXPORTED)) ||
  1412.          ((addwhat & CC_SCALARS)   &&  (hn->flags & PM_SCALAR))   ||
  1413.          ((addwhat & CC_READONLYS) &&  (hn->flags & PM_READONLY)) ||
  1414.          ((addwhat & CC_SPECIALS)  &&  (hn->flags & PM_SPECIAL))  ||
  1415.          ((addwhat & CC_PARAMS)    && !(hn->flags & PM_EXPORTED)) ||
  1416.         (((addwhat & CC_SHFUNCS)                  ||
  1417.           (addwhat & CC_BUILTINS)                  ||
  1418.           (addwhat & CC_EXTCMDS)                  ||
  1419.           (addwhat & CC_RESWDS)                      ||
  1420.          ((addwhat & CC_ALREG)     && !(hn->flags & ALIAS_GLOBAL)) ||
  1421.          ((addwhat & CC_ALGLOB)    &&  (hn->flags & ALIAS_GLOBAL))) &&
  1422.         (((addwhat & CC_DISCMDS) && (hn->flags & DISABLED)) ||
  1423.          ((addwhat & CC_EXCMDS) && !(hn->flags & DISABLED))))))) {
  1424.     if (sl >= rpl + rsl) {
  1425.         if (cp)
  1426.         test = domatch(s, patcomp, 0);
  1427.         else {
  1428.         e = s + sl - rsl;
  1429.         if ((test = !strncmp(s, rpre, rpl)))
  1430.             test = !strcmp(e, rsuf);
  1431.         }
  1432.     }
  1433.     if (!test && sl < lpl + lsl)
  1434.         return;
  1435.     if (!test && lpre && lsuf && sl >= lpl + lsl) {
  1436.         e = s + sl - lsl;
  1437.         if ((test = !strncmp(s, lpre, lpl)))
  1438.         test = !strcmp(e, lsuf);
  1439.         pl = lpl;
  1440.     }
  1441.     if (addwhat == CC_QUOTEFLAG) {
  1442.         te = s + pl;
  1443.         s = quotename(s, &e, te, &pl);
  1444.         sl = strlen(s);
  1445.     }
  1446.     if (test)
  1447.         haswhat |= HAS_MISC;
  1448.     }
  1449.     if (!test)
  1450.     return;
  1451.  
  1452.     if (ispattern) {
  1453.     t = s;
  1454.     } else {
  1455.     t = s += pl;
  1456.     if (*e) {
  1457.         sl = e - s;
  1458.         t = s = dupstring(t);
  1459.         s[sl] = '\0';
  1460.     }
  1461.     }
  1462.  
  1463.     if (l == fmatches) {
  1464.     bp = &fab;
  1465.     ep = &fae;
  1466.     sp = &fshortl;
  1467.     fm = &ffirstm;
  1468.     } else {
  1469.     bp = &ab;
  1470.     ep = &ae;
  1471.     sp = &shortl;
  1472.     fm = &firstm;
  1473.     }
  1474.  
  1475.     if (!ispattern && *fm) {
  1476.     if ((test = pfxlen(*fm, s)) < *bp)
  1477.         *bp = test;
  1478.     if ((test = sfxlen(*fm, s)) < *ep)
  1479.         *ep = test;
  1480.     }
  1481.  
  1482.     /* If we are doing a glob completion we store the whole string in *
  1483.      * the list. Otherwise only the part that fits between the prefix *
  1484.      * and the suffix is stored.                                      */
  1485.     addlinknode(l, t);
  1486.     if (!*fm) {
  1487.     *bp = *ep = 10000;
  1488.     *fm = t;
  1489.     *sp = 100000;
  1490.     }
  1491.     if (!ispattern && (sl = strlen(t)) < *sp) {
  1492.     *sp = sl;
  1493.     if (l == fmatches)
  1494.         fshortest = t;
  1495.     else
  1496.         shortest = t;
  1497.     }
  1498. }
  1499.  
  1500. #ifdef HAVE_NIS_PLUS
  1501. static int
  1502. match_username(nis_name table, nis_object *object, void *userdata)
  1503. {
  1504.     if (errflag)
  1505.     return 1;
  1506.     else {
  1507.     static char buf[40];
  1508.     register entry_col *ec =
  1509.         object->zo_data.objdata_u.en_data.en_cols.en_cols_val;
  1510.     register int l = minimum(ec->ec_value.ec_value_len, 39);
  1511.  
  1512.     memcpy(buf, ec->ec_value.ec_value_val, l);
  1513.     buf[l] = '\0';
  1514.  
  1515.     addmatch(dupstring(buf), NULL);
  1516.     }
  1517.     return 0;
  1518. }
  1519. #else
  1520. # ifdef HAVE_NIS
  1521. static int
  1522. match_username(int status, char *key, int keylen, char *val, int vallen, dopestring *data)
  1523. {
  1524.     if (errflag || status != YP_TRUE)
  1525.     return 1;
  1526.  
  1527.     if (vallen > keylen && val[keylen] == ':') {
  1528.     val[keylen] = '\0';
  1529.     addmatch(dupstring(val), NULL);
  1530.     }
  1531.     return 0;
  1532. }
  1533. # endif /* HAVE_NIS */
  1534. #endif  /* HAVE_NIS_PLUS */
  1535.  
  1536. /**/
  1537. void
  1538. maketildelist(void)
  1539. {
  1540. #if defined(HAVE_NIS) || defined(HAVE_NIS_PLUS)
  1541.     FILE *pwf;
  1542.     char buf[BUFSIZ], *p;
  1543.     int skipping;
  1544.  
  1545. # ifndef HAVE_NIS_PLUS
  1546.     char domain[YPMAXDOMAIN];
  1547.     struct ypall_callback cb;
  1548.     dopestring data;
  1549.  
  1550.     data.s = fpre;
  1551.     data.len = fpl;
  1552.     /* Get potential matches from NIS and cull those without local accounts */
  1553.     if (getdomainname(domain, YPMAXDOMAIN) == 0) {
  1554.     cb.foreach = (int ((*)()))match_username;
  1555.     cb.data = (char *)&data;
  1556.     yp_all(domain, PASSWD_MAP, &cb);
  1557. /*    for (n = firstnode(matches); n; incnode(n))
  1558.         if (getpwnam(getdata(n)) == NULL)
  1559.         uremnode(matches, n);*/
  1560.     }
  1561. # else  /* HAVE_NIS_PLUS */
  1562.        /* Maybe we should turn this string into a #define'd constant...? */
  1563.  
  1564.     nis_list("passwd.org_dir", EXPAND_NAME|ALL_RESULTS|FOLLOW_LINKS|FOLLOW_PATH,
  1565.          match_username, 0);
  1566. # endif
  1567.     /* Don't forget the non-NIS matches from the flat passwd file */
  1568.     if ((pwf = fopen(PASSWD_FILE, "r")) != NULL) {
  1569.     skipping = 0;
  1570.     while (fgets(buf, BUFSIZ, pwf) != NULL) {
  1571.         if (strchr(buf, '\n') != NULL) {
  1572.         if (!skipping) {
  1573.             if ((p = strchr(buf, ':')) != NULL) {
  1574.             *p = '\0';
  1575.             addmatch(dupstring(buf), NULL);
  1576.             }
  1577.         } else
  1578.             skipping = 0;
  1579.         } else
  1580.         skipping = 1;
  1581.     }
  1582.     fclose(pwf);
  1583.     }
  1584. #else  /* no NIS or NIS_PLUS */
  1585.     /* add all the usernames to the named directory table */
  1586.     nameddirtab->filltable(nameddirtab);
  1587. #endif
  1588.  
  1589.     scanhashtable(nameddirtab, 0, (addwhat==-1) ? 0 : ND_USERNAME, 0,
  1590.         addhnmatch, 0);
  1591. }
  1592.  
  1593. /* Copy the given string and remove backslashes from the copy and return it. */
  1594.  
  1595. /**/
  1596. char *
  1597. rembslash(char *s)
  1598. {
  1599.     char *t = s = dupstring(s);
  1600.  
  1601.     while (*s)
  1602.     if (*s == '\\') {
  1603.         chuck(s);
  1604.         if (*s)
  1605.         s++;
  1606.     } else
  1607.         s++;
  1608.  
  1609.     return t;
  1610. }
  1611.  
  1612. /* This does the check for compctl -x `n' and `N' patterns. */
  1613.  
  1614. /**/
  1615. int
  1616. getcpat(char *wrd, int cpatindex, char *cpat, int class)
  1617. {
  1618.     char *str, *s, *t, *p;
  1619.     int d = 0;
  1620.  
  1621.     if (!wrd || !*wrd)
  1622.     return -1;
  1623.  
  1624.     cpat = rembslash(cpat);
  1625.  
  1626.     str = ztrdup(wrd);
  1627.     untokenize(str);
  1628.     if (!cpatindex)
  1629.     cpatindex++, d = 0;
  1630.     else if ((d = (cpatindex < 0)))
  1631.     cpatindex = -cpatindex;
  1632.  
  1633.     for (s = d ? str + strlen(str) - 1 : str;
  1634.      d ? (s >= str) : *s;
  1635.      d ? s-- : s++) {
  1636.     for (t = s, p = cpat; *t && *p; p++) {
  1637.         if (class) {
  1638.         if (*p == *s && !--cpatindex) {
  1639.             zsfree(str);
  1640.             return (int)(s - str + 1);
  1641.         }
  1642.         } else if (*t++ != *p)
  1643.         break;
  1644.     }
  1645.     if (!class && !*p && !--cpatindex) {
  1646.         zsfree(str);
  1647.         t += wrd - str;
  1648.         for (d = 0; --t >= wrd;)
  1649.         if (! INULL(*t))
  1650.             d++;
  1651.         return d;
  1652.     }
  1653.     }
  1654.     zsfree(str);
  1655.     return -1;
  1656. }
  1657.  
  1658. /* This holds a pointer to the compctl we are using. */
  1659.  
  1660. Compctl ccmain;
  1661.  
  1662.  
  1663. /* Find the compctl to use and return it.  The first argument gives a *
  1664.  * compctl to start searching with (if it is zero, the hash table is  *
  1665.  * searched).  compadd is used to return a number of characters that  *
  1666.  * should be ignored at the beginning of the word and incmd is        *
  1667.  * non-zero if we are in command position.                            */
  1668.  
  1669. /**/
  1670. Compctl
  1671. get_ccompctl(Compctl occ, int *compadd, int incmd)
  1672. {
  1673.     Compctl compc, ret;
  1674.     Compctlp ccp;
  1675.     int t, i, a, b, tt, ra, rb, j, isf = 1;
  1676.     Compcond or, cc;
  1677.     char *s, *ss, *sc, *cmd = dupstring(cmdstr);
  1678.     Comp comp;
  1679.  
  1680.    first_rec:
  1681.     *compadd = 0;
  1682.     ra = 0;
  1683.     rb = clwnum - 1;
  1684.     sc = NULL;
  1685.  
  1686.     if (!(ret = compc = occ)) {
  1687.       if (isf) {
  1688.         isf = 0;
  1689.         ret = &cc_first;
  1690.       }
  1691.       else if (inwhat == IN_ENV)
  1692.         /* Default completion for parameter values. */
  1693.         ret = &cc_default;
  1694.       else if (inwhat == IN_MATH) {
  1695.         /* Parameter names inside mathematical expression. */
  1696.         cc_dummy.mask = CC_PARAMS;
  1697.         ret = &cc_dummy;
  1698.         cc_dummy.refc = 10000;
  1699.     } else if (inwhat == IN_COND) {
  1700.         /* We try to be clever here: in conditions we complete option   *
  1701.          * names after a `-o', file names after `-nt', `-ot', and `-ef' *
  1702.          * and file names and parameter names elsewhere.                */
  1703.         s = clwpos ? clwords[clwpos - 1] : "";
  1704.         cc_dummy.mask = !strcmp("-o", s) ? CC_OPTIONS :
  1705.         ((*s == '-' && s[1] && !s[2]) ||
  1706.          !strcmp("-nt", s) ||
  1707.          !strcmp("-ot", s) ||
  1708.          !strcmp("-ef", s)) ? CC_FILES :
  1709.         (CC_FILES | CC_PARAMS);
  1710.         ret = &cc_dummy;
  1711.         cc_dummy.refc = 10000;
  1712.     } else if (incmd)
  1713.         ret = &cc_compos;
  1714.     /* And in redirections or if there is no command name (and we are *
  1715.      * not in command position) or if no special compctl was given    *
  1716.      * for the command: use default completion.  Note that we first   *
  1717.      * search the complete command name and than the trailing         *
  1718.      * pathname component.                                            */
  1719.     else if (linredir ||
  1720.           !(cmd &&
  1721.             (((ccp = (Compctlp) compctltab->getnode(compctltab, cmd)) &&
  1722.              (compc = ret = ccp->cc)) ||
  1723.              ((s = dupstring(cmd)) && remlpaths(&s) &&
  1724.              (ccp = (Compctlp) compctltab->getnode(compctltab, s)) &&
  1725.              (compc = ret = ccp->cc)))))
  1726.         ret = &cc_default;
  1727.  
  1728.     ccmain = compc = ret;
  1729.     ccmain->refc++;
  1730.     }
  1731.     /* The compctl we found has extended completion patterns, check them. */
  1732.     if (compc && compc->ext) {
  1733.     compc = compc->ext;
  1734.     /* This loops over the patterns separated by `--'. */
  1735.     for (t = 0; compc && !t; compc = compc->next) {
  1736.         /* This loops over OR'ed patterns. */
  1737.         for (cc = compc->cond; cc && !t; cc = or) {
  1738.         or = cc->or;
  1739.         /* This loops over AND'ed patterns. */
  1740.         for (t = 1; cc && t; cc = cc->and) {
  1741.             /* And this loops of [...] pairs. */
  1742.             for (t = i = 0; i < cc->n && !t; i++) {
  1743.             s = NULL;
  1744.             ra = 0;
  1745.             rb = clwnum - 1;
  1746.             switch (cc->type) {
  1747.             case CCT_POS:
  1748.                 tt = clwpos;
  1749.                 goto cct_num;
  1750.             case CCT_NUMWORDS:
  1751.                 tt = clwnum;
  1752.               cct_num:
  1753.                 if ((a = cc->u.r.a[i]) < 0)
  1754.                 a += clwnum;
  1755.                 if ((b = cc->u.r.b[i]) < 0)
  1756.                 b += clwnum;
  1757.                 if (cc->type == CCT_POS)
  1758.                 ra = a, rb = b;
  1759.                 t = (tt >= a && tt <= b);
  1760.                 break;
  1761.             case CCT_CURSUF:
  1762.             case CCT_CURPRE:
  1763.                 s = ztrdup(clwpos < clwnum ? clwords[clwpos] : "");
  1764.                 untokenize(s);
  1765.                 sc = rembslash(cc->u.s.s[i]);
  1766.                 a = strlen(sc);
  1767.                 if (!strncmp(s, sc, a)) {
  1768.                 *compadd = (cc->type == CCT_CURSUF ? a : 0);
  1769.                 t = 1;
  1770.                 }
  1771.                 break;
  1772.             case CCT_CURSUB:
  1773.             case CCT_CURSUBC:
  1774.                 if (clwpos < 0 || clwpos > clwnum)
  1775.                 t = 0;
  1776.                 else {
  1777.                 a = getcpat(clwords[clwpos],
  1778.                         cc->u.s.p[i],
  1779.                         cc->u.s.s[i],
  1780.                         cc->type == CCT_CURSUBC);
  1781.                 if (a != -1)
  1782.                     *compadd = a, t = 1;
  1783.                 }
  1784.                 break;
  1785.  
  1786.             case CCT_CURPAT:
  1787.             case CCT_CURSTR:
  1788.                 tt = clwpos;
  1789.                 goto cct_str;
  1790.             case CCT_WORDPAT:
  1791.             case CCT_WORDSTR:
  1792.                 tt = 0;
  1793.               cct_str:
  1794.                 if ((a = tt + cc->u.s.p[i]) < 0)
  1795.                 a += clwnum;
  1796.                 s = ztrdup((a < 0 || a >= clwnum) ? "" :
  1797.                        clwords[a]);
  1798.                 untokenize(s);
  1799.  
  1800.                 if (cc->type == CCT_CURPAT ||
  1801.                 cc->type == CCT_WORDPAT) {
  1802.                 tokenize(ss = dupstring(cc->u.s.s[i]));
  1803.                 t = ((comp = parsereg(ss)) &&
  1804.                      domatch(s, comp, 0));
  1805.                 } else
  1806.                 t = (!strcmp(s, rembslash(cc->u.s.s[i])));
  1807.                 break;
  1808.             case CCT_RANGESTR:
  1809.             case CCT_RANGEPAT:
  1810.                 if (cc->type == CCT_RANGEPAT)
  1811.                 tokenize(sc = dupstring(cc->u.l.a[i]));
  1812.                 for (j = clwpos; j; j--) {
  1813.                 untokenize(s = ztrdup(clwords[j]));
  1814.                 if (cc->type == CCT_RANGESTR)
  1815.                     sc = rembslash(cc->u.l.a[i]);
  1816.                 if (cc->type == CCT_RANGESTR ?
  1817.                     !strncmp(s, sc, strlen(sc)) :
  1818.                     ((comp = parsereg(sc)) &&
  1819.                      domatch(s, comp, 0))) {
  1820.                     zsfree(s);
  1821.                     ra = j + 1;
  1822.                     t = 1;
  1823.                     break;
  1824.                 }
  1825.                 zsfree(s);
  1826.                 }
  1827.                 if (t) {
  1828.                 if (cc->type == CCT_RANGEPAT)
  1829.                     tokenize(sc = dupstring(cc->u.l.b[i]));
  1830.                 for (j++; j < clwnum; j++) {
  1831.                     untokenize(s = ztrdup(clwords[j]));
  1832.                     if (cc->type == CCT_RANGESTR)
  1833.                     sc = rembslash(cc->u.l.b[i]);
  1834.                     if (cc->type == CCT_RANGESTR ?
  1835.                     !strncmp(s, sc, strlen(sc)) :
  1836.                     ((comp = parsereg(sc)) &&
  1837.                      domatch(s, comp, 0))) {
  1838.                     zsfree(s);
  1839.                     rb = j - 1;
  1840.                     t = clwpos <= rb;
  1841.                     break;
  1842.                     }
  1843.                     zsfree(s);
  1844.                 }
  1845.                 }
  1846.                 s = NULL;
  1847.             }
  1848.             zsfree(s);
  1849.             }
  1850.         }
  1851.         }
  1852.         if (t)
  1853.         break;
  1854.     }
  1855.     if (compc)
  1856.         /* We found a matching pattern, we may return it. */
  1857.         ret = compc;
  1858.     }
  1859.     if (ret->subcmd) {
  1860.     /* The thing we want to return has a subcmd flag (-l). */
  1861.     char **ow = clwords, *os = cmdstr, *ops = NULL;
  1862.     int oldn = clwnum, oldp = clwpos;
  1863.  
  1864.     /* So we restrict the words-array. */
  1865.     if (ra >= clwnum)
  1866.         ra = clwnum - 1;
  1867.     if (ra < 1)
  1868.         ra = 1;
  1869.     if (rb >= clwnum)
  1870.         rb = clwnum - 1;
  1871.     if (rb < 1)
  1872.         rb = 1;
  1873.     clwnum = rb - ra + 1;
  1874.     clwpos = clwpos - ra;
  1875.  
  1876.     if (ret->subcmd[0]) {
  1877.         /* And probably put the command name given to the flag *
  1878.          * in the array.                                       */
  1879.         clwpos++;
  1880.         clwnum++;
  1881.         incmd = 0;
  1882.         ops = clwords[ra - 1];
  1883.         clwords[ra - 1] = cmdstr = ret->subcmd;
  1884.         clwords += ra - 1;
  1885.     } else {
  1886.         cmdstr = clwords[ra];
  1887.         incmd = !clwpos;
  1888.         clwords += ra;
  1889.     }
  1890.     *compadd = 0;
  1891.     if (ccmain != &cc_dummy)
  1892.         freecompctl(ccmain);
  1893.     /* Then we call this function recursively. */
  1894.  
  1895.     ret = get_ccompctl(NULL, compadd, incmd);
  1896.     /* And restore the things we changed. */
  1897.     clwords = ow;
  1898.     cmdstr = os;
  1899.     clwnum = oldn;
  1900.     clwpos = oldp;
  1901.     if (ops)
  1902.         clwords[ra - 1] = ops;
  1903.     }
  1904.     if (ret == &cc_first)
  1905.       goto first_rec;
  1906.     return ret;
  1907. }
  1908.  
  1909. /* Dump a hash table (without sorting).  For each element the addmatch  *
  1910.  * function is called and at the beginning the addwhat variable is set. *
  1911.  * This could be done using scanhashtable(), but this is easy and much  *
  1912.  * more efficient.                                                      */
  1913.  
  1914. /**/
  1915. void
  1916. dumphashtable(HashTable ht, int what)
  1917. {
  1918.     HashNode hn;
  1919.     int i;
  1920.  
  1921.     addwhat = what;
  1922.  
  1923.     for (i = 0; i < ht->hsize; i++)
  1924.     for (hn = ht->nodes[i]; hn; hn = hn->next)
  1925.         addmatch(hn->nam, (char *) hn);
  1926.  
  1927. }
  1928.  
  1929. /* ScanFunc used by maketildelist() et al. */
  1930.  
  1931. /**/
  1932. void
  1933. addhnmatch(HashNode hn, int flags)
  1934. {
  1935.     addmatch(hn->nam, NULL);
  1936. }
  1937.  
  1938. /* Perform expansion on the given string and return the result. *
  1939.  * During this errors are not reported.                         */
  1940.  
  1941. /**/
  1942. char *
  1943. getreal(char *str)
  1944. {
  1945.     LinkList l = newlinklist();
  1946.     int ne = noerrs;
  1947.  
  1948.     noerrs = 1;
  1949.     addlinknode(l, dupstring(str));
  1950.     prefork(l, 0);
  1951.     noerrs = ne;
  1952.     if (!errflag && nonempty(l))
  1953.     return ztrdup(peekfirst(l));
  1954.     errflag = 0;
  1955.  
  1956.     return ztrdup(str);
  1957. }
  1958.  
  1959. /* This reads a directory and adds the files to the list of  *
  1960.  * matches.  The parameters say which files should be added. */
  1961.  
  1962. /**/
  1963. void
  1964. gen_matches_files(int dirs, int execs, int all)
  1965. {
  1966.     DIR *d;
  1967.     struct dirent *de;
  1968.     struct stat buf;
  1969.     char *n, p[PATH_MAX], *q = NULL, *e;
  1970.     LinkList l = NULL;
  1971.     int ns = 0, ng = opts[NULLGLOB], test, aw = addwhat;
  1972.  
  1973.     addwhat = execs ? -8 : -5;
  1974.     opts[NULLGLOB] = 1;
  1975.  
  1976.     if (*psuf) {
  1977.     /* If there is a path suffix, check if it doesn't have a `*' or *
  1978.      * `)' at the end (this is used to determine if we should use   *
  1979.      * globbing).                                                   */
  1980.     q = psuf + strlen(psuf) - 1;
  1981.     ns = !(*q == Star || *q == Outpar);
  1982.     l = newlinklist();
  1983.     /* And generate only directory names. */
  1984.     dirs = 1;
  1985.     all = execs = 0;
  1986.     }
  1987.     /* Open directory. */
  1988.     if ((d = opendir((prpre && *prpre) ? prpre : "."))) {
  1989.     /* If we search only special files, prepare a path buffer for stat. */
  1990.     if (!all && prpre) {
  1991.         strcpy(p, prpre);
  1992.         q = p + strlen(prpre);
  1993.     }
  1994.     /* Fine, now read the directory. */
  1995.     while ((de = readdir(d)) && !errflag) {
  1996.         n = de->d_name;
  1997.         /* Ignore `.' and `..'. */
  1998.         if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0')))
  1999.         continue;
  2000.         /* Ignore files beginning with `.' unless the thing we found on *
  2001.          * the command line also starts with a dot or GLOBDOTS is set.  */
  2002.         if (*n != '.' || *fpre == '.' || isset(GLOBDOTS)) {
  2003.         if (filecomp)
  2004.             /* If we have a pattern for the filename check, use it. */
  2005.             test = domatch(n, filecomp, 0);
  2006.         else {
  2007.             /* Otherwise use the prefix and suffix strings directly. */
  2008.             e = n + strlen(n) - fsl;
  2009.             if ((test = !strncmp(n, fpre, fpl)))
  2010.             test = !strcmp(e, fsuf);
  2011.         }
  2012.         /* Filename didn't match? */
  2013.         if (!test)
  2014.             continue;
  2015.         if (!all) {
  2016.             /* We still have to check the file type, so prepare *
  2017.              * the path buffer by appending the filename.       */
  2018.             strcpy(q, n);
  2019.             /* And do the stat. */
  2020.             if (stat(p, &buf) < 0)
  2021.             continue;
  2022.         }
  2023.         if (all ||
  2024.             (dirs && (buf.st_mode & S_IFMT) == S_IFDIR) ||
  2025.             (execs && ((buf.st_mode & (S_IFMT | S_IEXEC))
  2026.               == (S_IFREG | S_IEXEC)))) {
  2027.             /* If we want all files or the file has the right type... */
  2028.             if (*psuf) {
  2029.             /* We have to test for a path suffix. */
  2030.             int o = strlen(p), tt;
  2031.  
  2032.             /* Append it to the path buffer. */
  2033.             strcpy(p + o, psuf);
  2034.  
  2035.             /* Do we have to use globbing? */
  2036.             if (ispattern || (ns && isset(GLOBCOMPLETE))) {
  2037.                 /* Yes, so append a `*' if needed. */
  2038.                 if (ns) {
  2039.                 int tl = strlen(p);
  2040.  
  2041.                 p[tl] = Star;
  2042.                 p[tl + 1] = '\0';
  2043.                 }
  2044.                 /* Do the globbing... */
  2045.                 remnulargs(p);
  2046.                 addlinknode(l, p);
  2047.                 globlist(l);
  2048.                 /* And see if that produced a filename. */
  2049.                 tt = nonempty(l);
  2050.                 while (ugetnode(l));
  2051.             } else
  2052.                 /* Otherwise just check, if we have access *
  2053.                  * to the file.                            */
  2054.                 tt = !access(p, F_OK);
  2055.  
  2056.             p[o] = '\0';
  2057.             if (tt)
  2058.                 /* Ok, we can add the filename to the *
  2059.                  * list of matches.                   */
  2060.                 addmatch(dupstring(n), NULL);
  2061.             } else
  2062.             /* We want all files, so just add the name *
  2063.              * to the matches.                         */
  2064.             addmatch(dupstring(n), NULL);
  2065.         }
  2066.         }
  2067.     }
  2068.     closedir(d);
  2069.     }
  2070.     opts[NULLGLOB] = ng;
  2071.     addwhat = aw;
  2072. }
  2073.  
  2074. /* This holds the explanation string we have to print. */
  2075.  
  2076. char *expl;
  2077.  
  2078. /* This holds the suffix to add (given with compctl -S). */
  2079.  
  2080. char *ccsuffix;
  2081.  
  2082. /* This s non-zero if the compctl -q flag was given (the suffix should *
  2083.  * be removed when a space or something like that is typed next).      */
  2084.  
  2085. int remsuffix;
  2086.  
  2087. /**/
  2088. void
  2089. quotepresuf(char **ps)
  2090. {
  2091.     if (*ps) {
  2092.     char *p = quotename(*ps, NULL, NULL, NULL);
  2093.  
  2094.     if (p != *ps) {
  2095.         zsfree(*ps);
  2096.         *ps = ztrdup(p);
  2097.     }
  2098.     }
  2099. }
  2100.  
  2101. /* This is non-zero if the cursor was moved up after showing a list *
  2102.  * of completions (with alwayslastprompt).                          */
  2103.  
  2104. int clearflag;
  2105.  
  2106. /**/
  2107. void
  2108. docompletion(char *s, int lst, int incmd)
  2109. {
  2110.     static int delit, compadd;
  2111.  
  2112.     HEAPALLOC {
  2113.     pushheap();
  2114.  
  2115.     /* Make sure we have the completion list and compctl. */
  2116.     if(makecomplist(s, incmd, &delit, &compadd)) {
  2117.         /* Error condition: feeeeeeeeeeeeep(). */
  2118.         feep();
  2119.         goto compend;
  2120.     }
  2121.  
  2122.     if (lst == COMP_LIST_COMPLETE)
  2123.         /* All this and the guy only wants to see the list, sigh. */
  2124.         showinglist = -2;
  2125.     else {
  2126.         /* We have matches. */
  2127.         if (delit) {
  2128.         /* If we have to delete the word from the command line, *
  2129.          * do it now.                                           */
  2130.         wb -= compadd;
  2131.         strcpy((char *)line + wb, (char *)line + we);
  2132.         we = cs = wb;
  2133.         }
  2134.         if (nmatches>1)
  2135.         /* There are more than one match. */
  2136.         do_ambiguous();
  2137.         else {
  2138.         /* Only one match. */
  2139.         do_single(amatches[0]);
  2140.         invalidatelist();
  2141.         }
  2142.     }
  2143.  
  2144.     /* Print the explanation string if needed. */
  2145.     if (!showinglist && expl && nmatches!=1) {
  2146.         int up;
  2147.  
  2148.         trashzle();
  2149.  
  2150.         clearflag = (isset(USEZLE) && termok &&
  2151.              (isset(ALWAYSLASTPROMPT) && zmult == 1)) ||
  2152.             (unset(ALWAYSLASTPROMPT) && zmult != 1);
  2153.  
  2154.         up = printfmt(expl, nmatches, 1);
  2155.  
  2156.         if (clearflag)
  2157.         tcmultout(TCUP, TCMULTUP, up + nlnct);
  2158.         else
  2159.         putc('\n', shout);
  2160.         fflush(shout);
  2161.     }
  2162.       compend:
  2163.     ll = strlen((char *)line);
  2164.     if (cs > ll)
  2165.         cs = ll;
  2166.     popheap();
  2167.     } LASTALLOC;
  2168. }
  2169.  
  2170. /* Create the completion list.  This is called whenever some bit of  *
  2171.  * completion code needs the list.  If the list is already available *
  2172.  * (validlist!=0), this function doesn't do anything.  Along with    *
  2173.  * the list is maintained the prefixes/suffixes etc.  When any of    *
  2174.  * this becomes invalid -- e.g. if some text is changed on the       *
  2175.  * command line -- invalidatelist() should be called, to set         *
  2176.  * validlist to zero and free up the memory used.  This function     *
  2177.  * returns non-zero on error.  delit and compadd return information  *
  2178.  * about bits of the command line that need to be deleted.           */
  2179.  
  2180. /**/
  2181. int
  2182. makecomplist(char *s, int incmd, int *delit, int *compadd)
  2183. {
  2184.     Compctl cc = NULL;
  2185.     int oloffs = offs, owe = we, owb = wb, ocs = cs, isf = 1;
  2186.     int t, sf1, sf2, ooffs;
  2187.     char *p, *sd = NULL, sav, *tt, *s1, *s2, *os = NULL;
  2188.     unsigned char *ol = NULL;
  2189.  
  2190.     /* If we already have a list from a previous execution of this *
  2191.      * function, skip the list building code.                      */
  2192.     if (validlist)
  2193.     return !nmatches;
  2194.  
  2195.     os = dupstring(s);
  2196.     ol = (unsigned char *)dupstring((char *)line);
  2197.  
  2198.   xorrec:
  2199.  
  2200.     /* Go to the end of the word if complete_in_word is not set. */
  2201.     if (unset(COMPLETEINWORD) && cs != we)
  2202.     cs = we, offs = strlen(s);
  2203.  
  2204.     ispattern = haswhat = lastambig = 0;
  2205.     patcomp = filecomp = NULL;
  2206.     menucur = NULL;
  2207.     shortest = NULL;
  2208.     fshortest = NULL;
  2209.     rpre = rsuf = lpre = lsuf = ppre = psuf = prpre =
  2210.     fpre = fsuf = firstm = ffirstm = parampre = qparampre = NULL;
  2211.  
  2212.     /* Blank out the lists. */
  2213.     matches = newlinklist();
  2214.     fmatches = newlinklist();
  2215.  
  2216.     /* If we don't have a compctl definition yet or we have a compctl *
  2217.      * with extended completion, get it (or the next one, resp.).     */
  2218.     if (!cc || cc->ext)
  2219.     cc = get_ccompctl(cc, compadd, incmd);
  2220.  
  2221.     /* *compadd is the number of characters we have to ignore at the *
  2222.      * beginning of the word.                                        */
  2223.     wb += *compadd;
  2224.     s += *compadd;
  2225.     if ((offs -= *compadd) < 0) {
  2226.     /* It's bigger than our word prefix, so we can't help here... */
  2227.     feep();
  2228.     return 1;
  2229.     }
  2230.  
  2231.     /* Insert the prefix (compctl -P), if any. */
  2232.     if (cc->prefix) {
  2233.     int pl = 0, sl = strlen(cc->prefix);
  2234.  
  2235.     if (*s) {
  2236.         /* First find out how much of the prefix is already on the line. */
  2237.         sd = dupstring(s);
  2238.         untokenize(sd);
  2239.         pl = pfxlen(cc->prefix, sd);
  2240.         s += pl;
  2241.     }
  2242.     if (pl < sl) {
  2243.         int savecs = cs;
  2244.  
  2245.         /* Then insert the prefix. */
  2246.         cs = wb + pl;
  2247.         inststrlen(cc->prefix + pl, 0, sl - pl);
  2248.         cs = savecs + sl - pl;
  2249.     }
  2250.     /* And adjust the word beginning/end variables. */
  2251.     wb += sl;
  2252.     we += sl - pl;
  2253.     offs -= pl;
  2254.     }
  2255.     /* Does this compctl have a suffix (compctl -S)? */
  2256.     if ((ccsuffix = cc->suffix) && *ccsuffix) {
  2257.     char *sdup = dupstring(ccsuffix);
  2258.     int sl = strlen(sdup), suffixll;
  2259.  
  2260.     /* Ignore trailing spaces. */
  2261.     for (p = sdup + sl - 1; p >= sdup && *p == ' '; p--, sl--);
  2262.     p[1] = '\0';
  2263.  
  2264.     if (!sd) {
  2265.         sd = dupstring(s);
  2266.         untokenize(sd);
  2267.     }
  2268.     /* If the suffix is already there, ignore it (and don't add *
  2269.      * it again).                                               */
  2270.     if (*sd && (suffixll = strlen(sd)) >= sl &&
  2271.         !strcmp(sdup, sd + suffixll - sl)) {
  2272.         ccsuffix = NULL;
  2273.         haswhat |= HAS_SUFFIX;
  2274.         s[suffixll - sl] = '\0';
  2275.     }
  2276.     }
  2277.     /* Do we have one of the special characters `~' and `=' at the beginning? */
  2278.     if ((ic = *s) != Tilde && ic != Equals)
  2279.     ic = 0;
  2280.  
  2281.     /* Check if we have to complete a parameter name... */
  2282.  
  2283.     complexpect = menuce = 0;
  2284.  
  2285.     /* Try to find a `$'. */
  2286.     for (p = s + offs; p > s && *p != String; p--);
  2287.     if (*p == String) {
  2288.     /* Handle $$'s */
  2289.     while (p > s && p[-1] == String)
  2290.         p--;
  2291.     while (p[1] == String && p[2] == String)
  2292.         p += 2;
  2293.     }
  2294.     if (*p == String &&    p[1] != Inpar && p[1] != Inbrack) {
  2295.     /* This is really a parameter expression (not $(...) or $[...]). */
  2296.     char *b = p + 1, *e = b;
  2297.     int n = 0, br = 1;
  2298.  
  2299.     if (*b == Inbrace) {
  2300.         /* If this is a ${...}, ignore the possible (...) flags. */
  2301.         b++, br++;
  2302.         n = skipparens(Inpar, Outpar, &b);
  2303.     }
  2304.  
  2305.     /* Ignore the stuff before the parameter name. */
  2306.     for (; *b; b++)
  2307.         if (*b != '^' && *b != Hat &&
  2308.         *b != '=' && *b != Equals &&
  2309.         *b != '~' && *b != Tilde)
  2310.         break;
  2311.     if (*b == '#' || *b == Pound || *b == '+')
  2312.         b++;
  2313.  
  2314.     e = b;
  2315.     /* Find the end of the name. */
  2316.     if (*e == Quest || *e == Star || *e == String || *e == Qstring ||
  2317.         *e == '?'   || *e == '*'  || *e == '$'    ||
  2318.         *e == '-'   || *e == '!'  || *e == '@')
  2319.         e++;
  2320.     else if (idigit(*e))
  2321.         while (idigit(*e))
  2322.         e++;
  2323.     else if (iident(*e))
  2324.         while (iident(*e) ||
  2325.            (useglob && (*e == Star || *e == Quest)))
  2326.         e++;
  2327.  
  2328.     /* Now make sure that the cursor is inside the name. */
  2329.     if (offs <= e - s && offs >= b - s && n <= 0) {
  2330.         /* It is, set complexpect. */
  2331.         if (cs == we || ! *e || *e == ' ')
  2332.         complexpect = br;
  2333.         /* Get the prefix (anything up to the character before the name). */
  2334.         *e = '\0';
  2335.         sav = *b;
  2336.         *b = '\0';
  2337.         parampre = ztrdup(s);
  2338.         qparampre = ztrdup(quotename(s, NULL, NULL, NULL));
  2339.         untokenize(qparampre);
  2340.         qparprelen = strlen(qparampre);
  2341.         *b = sav;
  2342.         /* And adjust wb, we, and offs again. */
  2343.         offs -= b - s;
  2344.         wb = cs - offs;
  2345.         we = wb + e - b;
  2346.         s = b;
  2347.         /* And now make sure that we complete parameter names. */
  2348.         cc = ccmain = &cc_dummy;
  2349.         cc_dummy.refc = 10000;
  2350.         cc_dummy.mask = CC_PARAMS | CC_ENVVARS;
  2351.     } else
  2352.         complexpect = 0;
  2353.     }
  2354.     ooffs = offs;
  2355.     /* If we have to ignore the word, do that. */
  2356.     if (cc->mask & CC_DELETE) {
  2357.     *delit = 1;
  2358.     *s = '\0';
  2359.     offs = 0;
  2360.     } else
  2361.     *delit = 0;
  2362.  
  2363.     /* Compute line prefix/suffix. */
  2364.  
  2365.     lpl = offs;
  2366.     lpre = zalloc(lpl + 1);
  2367.     memcpy(lpre, s, lpl);
  2368.     lpre[lpl] = '\0';
  2369.     p = quotename(lpre, NULL, NULL, NULL);
  2370.     if (strcmp(p, lpre) && !strpfx(p, qword)) {
  2371.     int l1, l2;
  2372.  
  2373.     backdel(l1 = cs - wb);
  2374.     untokenize(p);
  2375.     inststrlen(p, 1, l2 = strlen(p));
  2376.     we += l2 - l1;
  2377.     }
  2378.     lsuf = ztrdup(s + offs);
  2379.     lsl = strlen(lsuf);
  2380.     if (lsl && (p = quotename(lsuf, NULL, NULL, NULL)) &&
  2381.     (strcmp(p, lsuf) && !strsfx(p, qword))) {
  2382.     int l1, l2;
  2383.  
  2384.     foredel(l1 = strlen(s + offs));
  2385.     untokenize(p);
  2386.     inststrlen(p, 0, l2 = strlen(p));
  2387.     we += l2 - l1;
  2388.     }
  2389.  
  2390.     /* First check for ~.../... */
  2391.     if (ic == Tilde) {
  2392.     for (p = lpre + lpl; p > lpre; p--)
  2393.         if (*p == '/')
  2394.         break;
  2395.  
  2396.     if (*p == '/')
  2397.         ic = 0;
  2398.     }
  2399.     /* Compute real prefix/suffix. */
  2400.  
  2401.     noreal = !*delit;
  2402.     for (p = lpre; *p && *p != String && *p != Tick; p++);
  2403.     tt = ic && !parampre ? lpre + 1 : lpre;
  2404.     rpre = (*p || *lpre == Tilde || *lpre == Equals) ?
  2405.     (noreal = 0, getreal(tt)) :
  2406.     ztrdup(tt);
  2407.  
  2408.     for (p = lsuf; *p && *p != String && *p != Tick; p++);
  2409.     rsuf = *p ? (noreal = 0, getreal(lsuf)) : ztrdup(lsuf);
  2410.  
  2411.     /* Check if word is a pattern. */
  2412.  
  2413.     for (s1 = NULL, sf1 = 0, p = rpre + (rpl = strlen(rpre)) - 1;
  2414.      p >= rpre && (ispattern != 3 || !sf1);
  2415.      p--)
  2416.     if (itok(*p) && (p > rpre || (*p != Equals && *p != Tilde)))
  2417.         ispattern |= sf1 ? 1 : 2;
  2418.     else if (*p == '/') {
  2419.         sf1++;
  2420.         if (!s1)
  2421.         s1 = p;
  2422.     }
  2423.     for (s2 = NULL, sf2 = t = 0, p = rsuf; *p && (!t || !sf2); p++)
  2424.     if (itok(*p))
  2425.         t |= sf2 ? 4 : 2;
  2426.     else if (*p == '/') {
  2427.         sf2++;
  2428.         if (!s2)
  2429.         s2 = p;
  2430.     }
  2431.     ispattern = ispattern | t;
  2432.  
  2433.     /* But if we were asked not to do glob completion, we never treat the *
  2434.      * thing as a pattern.                                                */
  2435.     if (!useglob)
  2436.     ispattern = 0;
  2437.  
  2438.     if (ispattern) {
  2439.     /* The word should be treated as a pattern, so compute the matcher. */
  2440.     p = (char *)ncalloc(rpl + rsl + 2);
  2441.     strcpy(p, rpre);
  2442.     if (rpl && p[rpl - 1] != Star) {
  2443.         p[rpl] = Star;
  2444.         strcpy(p + rpl + 1, rsuf);
  2445.     } else
  2446.         strcpy(p + rpl, rsuf);
  2447.     patcomp = parsereg(p);
  2448.     }
  2449.     if (!patcomp) {
  2450.     untokenize(rpre);
  2451.     untokenize(rsuf);
  2452.  
  2453.     rpl = strlen(rpre);
  2454.     rsl = strlen(rsuf);
  2455.     }
  2456.     untokenize(lpre);
  2457.     untokenize(lsuf);
  2458.  
  2459.     /* Handle completion of files specially (of course). */
  2460.  
  2461.     if ((cc->mask & (CC_FILES | CC_COMMPATH)) || cc->glob) {
  2462.     /* s1 and s2 point to the last/first slash in the prefix/suffix. */
  2463.     if (!s1)
  2464.         s1 = rpre;
  2465.     if (!s2)
  2466.         s2 = rsuf + rsl;
  2467.  
  2468.     /* Compute the path prefix/suffix. */
  2469.     if (*s1 != '/')
  2470.         ppre = ztrdup("");
  2471.     else {
  2472.         if ((sav = *s1 ? s1[1] : '\0'))
  2473.         s1[1] = '\0';
  2474.         ppre = ztrdup(rpre);
  2475.         if (sav)
  2476.         s1[1] = sav;
  2477.     }
  2478.     psuf = ztrdup(s2);
  2479.  
  2480.     /* And get the file prefix. */
  2481.     fpre = ztrdup(((s1 == s || s1 == rpre || ic) &&
  2482.                (*s != '/' || cs == wb)) ? s1 : s1 + 1);
  2483.     /* And the suffix. */
  2484.     sav = *s2;
  2485.     *s2 = '\0';
  2486.     fsuf = ztrdup(rsuf);
  2487.     *s2 = sav;
  2488.  
  2489.     if (useglob && (ispattern & 2)) {
  2490.         int t2;
  2491.  
  2492.         /* We have to use globbing, so compute the pattern from *
  2493.          * the file prefix and suffix with a `*' between them.  */
  2494.         p = (char *)ncalloc((t2 = strlen(fpre)) + strlen(fsuf) + 2);
  2495.         strcpy(p, fpre);
  2496.         if ((!t2 || p[t2 - 1] != Star) && *fsuf != Star)
  2497.         p[t2++] = Star;
  2498.         strcpy(p + t2, fsuf);
  2499.         filecomp = parsereg(p);
  2500.     }
  2501.     if (!filecomp) {
  2502.         untokenize(fpre);
  2503.         untokenize(fsuf);
  2504.  
  2505.         fpl = strlen(fpre);
  2506.         fsl = strlen(fsuf);
  2507.     }
  2508.     addwhat = -1;
  2509.  
  2510.     /* Completion after `~', maketildelist adds the usernames *
  2511.      * and named directories.                                 */
  2512.     if (ic == Tilde)
  2513.         maketildelist();
  2514.     else if (ic == Equals) {
  2515.         /* Completion after `=', get the command names from *
  2516.          * the cmdnamtab and aliases from aliastab.         */
  2517.         if (isset(HASHLISTALL))
  2518.         cmdnamtab->filltable(cmdnamtab);
  2519.         dumphashtable(cmdnamtab, -7);
  2520.         dumphashtable(aliastab, -2);
  2521.     } else {
  2522.         /* Normal file completion... */
  2523.         if (ispattern & 1) {
  2524.         /* But with pattern matching. */
  2525.         LinkList l = newlinklist();
  2526.         LinkNode n;
  2527.         int ng = opts[NULLGLOB];
  2528.  
  2529.         opts[NULLGLOB] = 1;
  2530.  
  2531.         addwhat = 0;
  2532.         p = (char *)ncalloc(lpl + lsl + 3);
  2533.         strcpy(p, lpre);
  2534.         if (*lsuf != '*' && *lpre && lpre[lpl - 1] != '*')
  2535.             strcat(p, "*");
  2536.         strcat(p, lsuf);
  2537.         if (*lsuf && lsuf[lsl - 1] != '*' && lsuf[lsl - 1] != ')')
  2538.             strcat(p, "*");
  2539.  
  2540.         /* Do the globbing. */
  2541.         tokenize(p);
  2542.         remnulargs(p);
  2543.         addlinknode(l, p);
  2544.         globlist(l);
  2545.  
  2546.         if (nonempty(l)) {
  2547.             /* And add the resulting words. */
  2548.             haswhat |= HAS_PATHPAT;
  2549.             for (n = firstnode(l); n; incnode(n))
  2550.             addmatch(getdata(n), NULL);
  2551.         }
  2552.         opts[NULLGLOB] = ng;
  2553.         } else {
  2554.         /* No pattern matching. */
  2555.         addwhat = CC_FILES;
  2556.         prpre = ztrdup(ppre);
  2557.  
  2558.         if (sf2)
  2559.             /* We are in the path, so add only directories. */
  2560.             gen_matches_files(1, 0, 0);
  2561.         else {
  2562.             if (cc->mask & CC_FILES)
  2563.             /* Add all files. */
  2564.             gen_matches_files(0, 0, 1);
  2565.             else if (cc->mask & CC_COMMPATH) {
  2566.             /* Completion of command paths. */
  2567.             if (sf1)
  2568.                 /* There is a path prefix, so add *
  2569.                  * directories and executables.   */
  2570.                 gen_matches_files(1, 1, 0);
  2571.             else {
  2572.                 /* No path prefix, so add the things *
  2573.                  * reachable via the PATH variable.  */
  2574.                 char **pc = path, *pp = prpre;
  2575.  
  2576.                 for (; *pc; pc++)
  2577.                 if (pc[0][0] == '.' && !pc[0][1])
  2578.                     break;
  2579.                 if (*pc) {
  2580.                 prpre = "./";
  2581.                 gen_matches_files(1, 1, 0);
  2582.                 prpre = pp;
  2583.                 }
  2584.             }
  2585.             }
  2586.             /* The compctl has a glob pattern (compctl -g). */
  2587.             if (cc->glob) {
  2588.             int ns, pl = strlen(prpre), o;
  2589.             char *g = dupstring(cc->glob), pa[PATH_MAX];
  2590.             char *p2, *p3;
  2591.             int ne = noerrs, md = opts[MARKDIRS];
  2592.  
  2593.             /* These are used in the globbing code to make *
  2594.              * things a bit faster.                        */
  2595.             glob_pre = fpre;
  2596.             glob_suf = fsuf;
  2597.  
  2598.             noerrs = 1;
  2599.             addwhat = -6;
  2600.             strcpy(pa, prpre);
  2601.             o = strlen(pa);
  2602.             opts[MARKDIRS] = 0;
  2603.  
  2604.             /* The compctl -g string may contain more than *
  2605.              * one pattern, so we need a loop.             */
  2606.             while (*g) {
  2607.                 LinkList l = newlinklist();
  2608.                 int ng;
  2609.  
  2610.                 /* Find the blank terminating the pattern. */
  2611.                 while (*g && inblank(*g))
  2612.                 g++;
  2613.                 /* Oops, we already reached the end of the
  2614.                    string. */
  2615.                 if (!*g)
  2616.                 break;
  2617.                 for (p = g + 1; *p && !inblank(*p); p++)
  2618.                 if (*p == '\\' && p[1])
  2619.                     p++;
  2620.                 sav = *p;
  2621.                 *p = '\0';
  2622.                 /* Get the pattern string. */
  2623.                 tokenize(g = dupstring(g));
  2624.                 if (*g == '=')
  2625.                 *g = Equals;
  2626.                 if (*g == '~')
  2627.                 *g = Tilde;
  2628.                 remnulargs(g);
  2629.                 if (*g == Equals || *g == Tilde) {
  2630.                 /* The pattern has a `~' or `=' at the  *
  2631.                  * beginning, so we expand this and use *
  2632.                  * the result.                          */
  2633.                 filesub(&g, 0);
  2634.                 addlinknode(l, dupstring(g));
  2635.                 } else if (*g == '/')
  2636.                 /* The pattern is a full path (starting *
  2637.                  * with '/'), so add it unchanged.      */
  2638.                 addlinknode(l, dupstring(g));
  2639.                 else {
  2640.                 /* It's a simple pattern, so append it to *
  2641.                  * the path we have on the command line.  */
  2642.                 strcpy(pa + o, g);
  2643.                 addlinknode(l, dupstring(pa));
  2644.                 }
  2645.                 /* Do the globbing. */
  2646.                 ng = opts[NULLGLOB];
  2647.                 opts[NULLGLOB] = 1;
  2648.                 globlist(l);
  2649.                 opts[NULLGLOB] = ng;
  2650.                 /* Get the results. */
  2651.                 if (nonempty(l) && peekfirst(l)) {
  2652.                 for (p2 = (char *)peekfirst(l); *p2; p2++)
  2653.                     if (itok(*p2))
  2654.                     break;
  2655.                 if (!*p2) {
  2656.                     if (*g == Equals || *g == Tilde ||
  2657.                     *g == '/') {
  2658.                     /* IF the pattern started with `~',  *
  2659.                      * `=', or `/', add the result only, *
  2660.                      * if it realy matches what we have  *
  2661.                      * on the line.                      */
  2662.                     while ((p2 = (char *)ugetnode(l)))
  2663.                         if (strpfx(prpre, p2))
  2664.                         addmatch(p2 + pl, NULL);
  2665.                     } else {
  2666.                     /* Otherwise ignore the path we *
  2667.                      * prepended to the pattern.    */
  2668.                     while ((p2 = p3 =
  2669.                         (char *)ugetnode(l))) {
  2670.                         for (ns = sf1; *p3 && ns; p3++)
  2671.                         if (*p3 == '/')
  2672.                             ns--;
  2673.  
  2674.                         addmatch(p3, NULL);
  2675.                     }
  2676.                     }
  2677.                 }
  2678.                 }
  2679.                 pa[o] = '\0';
  2680.                 *p = sav;
  2681.                 g = p;
  2682.             }
  2683.             glob_pre = glob_suf = NULL;
  2684.             noerrs = ne;
  2685.             opts[MARKDIRS] = md;
  2686.             }
  2687.         }
  2688.         }
  2689.     }
  2690.     }
  2691.     /* Use tricat() instead of dyncat() to get zalloc()'d memory. */
  2692.     if (ic) {
  2693.     /* Now change the `~' and `=' tokens to the real characters so *
  2694.      * that things starting with these characters will be added.   */
  2695.     char *orpre = rpre;
  2696.  
  2697.     rpre = tricat("", (ic == Tilde) ? "~" : "=", rpre);
  2698.     rpl++;
  2699.     zsfree(orpre);
  2700.     }
  2701.     if (!ic && (cc->mask & CC_COMMPATH) && !*ppre && !*psuf) {
  2702.     /* If we have to complete commands, add alias names, *
  2703.      * shell functions and builtins too.                 */
  2704.     dumphashtable(aliastab, -3);
  2705.     dumphashtable(reswdtab, -3);
  2706.     dumphashtable(shfunctab, -3);
  2707.     dumphashtable(builtintab, -3);
  2708.     if (isset(HASHLISTALL))
  2709.         cmdnamtab->filltable(cmdnamtab);
  2710.     dumphashtable(cmdnamtab, -3);
  2711.     /* And parameter names if autocd and cdablevars are set. */
  2712.     if (isset(AUTOCD) && isset(CDABLEVARS))
  2713.         dumphashtable(paramtab, -4);
  2714.     }
  2715.     addwhat = (cc->mask & CC_QUOTEFLAG) ? -2 : CC_QUOTEFLAG;
  2716.  
  2717.     if (cc->mask & CC_NAMED)
  2718.     /* Add named directories. */
  2719.     scanhashtable(nameddirtab, 0, 0, 0, addhnmatch, 0);
  2720.     if (cc->mask & CC_OPTIONS) {
  2721.     /* Add option names. */
  2722.     struct option *o;
  2723.  
  2724.     for (o = optns + OPT_SIZE; (--o)->name; )
  2725.         addmatch(dupstring(o->name), NULL);
  2726.     }
  2727.     if (cc->mask & CC_VARS)
  2728.     /* And parameter names. */
  2729.     dumphashtable(paramtab, -2);
  2730.     if (cc->mask & CC_BINDINGS) {
  2731.     /* And zle function names... */
  2732.     int t0;
  2733.  
  2734.     for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
  2735.         if (*zlecmds[t0].name)
  2736.         addmatch(dupstring(zlecmds[t0].name), NULL);
  2737.     }
  2738.     if (cc->keyvar) {
  2739.     /* This adds things given to the compctl -k flag *
  2740.      * (from a parameter or a list of words).        */
  2741.     char **usr = get_user_var(cc->keyvar);
  2742.  
  2743.     if (usr)
  2744.         while (*usr)
  2745.         addmatch(*usr++, NULL);
  2746.     }
  2747.     if (cc->mask & CC_USERS)
  2748.     /* Add user names. */
  2749.     maketildelist();
  2750.     if (cc->func) {
  2751.     /* This handles the compctl -K flag. */
  2752.     List list;
  2753.     char **r;
  2754.     int lv = lastval;
  2755.  
  2756.     /* Get the function. */
  2757.     if ((list = getshfunc(cc->func))) {
  2758.         /* We have it, so build a argument list. */
  2759.         LinkList args = newlinklist();
  2760.  
  2761.         addlinknode(args, cc->func);
  2762.  
  2763.         if (*delit) {
  2764.         sav = os[ooffs];
  2765.         os[ooffs] = '\0';
  2766.         p = dupstring(os);
  2767.         untokenize(p);
  2768.         addlinknode(args, p);
  2769.         os[ooffs] = sav;
  2770.         p = dupstring(os + ooffs);
  2771.         untokenize(p);
  2772.         addlinknode(args, p);
  2773.         } else {
  2774.         addlinknode(args, lpre);
  2775.         addlinknode(args, lsuf);
  2776.         }
  2777.  
  2778.         /* This flag allows us to use read -l and -c. */
  2779.         inzlefunc = 1;
  2780.         /* Call the function. */
  2781.         doshfunc(list, args, 0, 1);
  2782.         inzlefunc = 0;
  2783.         /* And get the result from the reply parameter. */
  2784.         if ((r = get_user_var("reply")))
  2785.         while (*r)
  2786.             addmatch(*r++, NULL);
  2787.     }
  2788.     lastval = lv;
  2789.     }
  2790.     if (cc->mask & (CC_JOBS | CC_RUNNING | CC_STOPPED)) {
  2791.     /* Get job names. */
  2792.     int i;
  2793.     char *j, *jj;
  2794.  
  2795.     for (i = 0; i < MAXJOB; i++)
  2796.         if (jobtab[i].stat & STAT_INUSE) {
  2797.         int stopped = jobtab[i].stat & STAT_STOPPED;
  2798.  
  2799.         j = jj = dupstring(jobtab[i].procs->text);
  2800.         /* Find the first word. */
  2801.         for (; *jj; jj++)
  2802.             if (*jj == ' ') {
  2803.             *jj = '\0';
  2804.             break;
  2805.             }
  2806.         if ((cc->mask & CC_JOBS) ||
  2807.             (stopped && (cc->mask & CC_STOPPED)) ||
  2808.             (!stopped && (cc->mask & CC_RUNNING)))
  2809.             addmatch(j, NULL);
  2810.         }
  2811.     }
  2812.     if (cc->str) {
  2813.     /* Get the stuff from a compctl -s. */
  2814.     LinkList foo = newlinklist();
  2815.     LinkNode n;
  2816.     int first = 1, ng = opts[NULLGLOB], oowe = we, oowb = wb;
  2817.     char *tmpbuf;
  2818.  
  2819.     opts[NULLGLOB] = 1;
  2820.  
  2821.     /* Put the strin in the lexer buffer and call the lexer to *
  2822.      * get the words we have to expand.                        */
  2823.     zleparse = 1;
  2824.     lexsave();
  2825.     tmpbuf = (char *)halloc(strlen(cc->str) + 5);
  2826.     sprintf(tmpbuf, "foo %s", cc->str); /* KLUDGE! */
  2827.     inpush(tmpbuf, 0);
  2828.     strinbeg();
  2829.     noaliases = 1;
  2830.     do {
  2831.         ctxtlex();
  2832.         if (tok == ENDINPUT || tok == LEXERR)
  2833.         break;
  2834.         if (!first && tokstr && *tokstr)
  2835.         addlinknode(foo, ztrdup(tokstr));
  2836.         first = 0;
  2837.     } while (tok != ENDINPUT && tok != LEXERR);
  2838.     noaliases = 0;
  2839.     strinend();
  2840.     inpop();
  2841.     errflag = zleparse = 0;
  2842.     lexrestore();
  2843.     /* Fine, now do full expansion. */
  2844.     prefork(foo, 0);
  2845.     if (!errflag) {
  2846.         globlist(foo);
  2847.         if (!errflag)
  2848.         /* And add the resulting words as matches. */
  2849.         for (n = firstnode(foo); n; incnode(n))
  2850.             addmatch((char *)n->dat, NULL);
  2851.     }
  2852.     opts[NULLGLOB] = ng;
  2853.     we = oowe;
  2854.     wb = oowb;
  2855.     }
  2856.     if (cc->hpat) {
  2857.     /* We have a pattern to take things from the history. */
  2858.     Comp compc = NULL;
  2859.     char *e, *h, hpatsav;
  2860.     Histent he;
  2861.     int i = curhist - 1, n = cc->hnum;
  2862.  
  2863.     /* Parse the pattern, if it isn't the null string. */
  2864.     if (*(cc->hpat)) {
  2865.         char *thpat = dupstring(cc->hpat);
  2866.  
  2867.         tokenize(thpat);
  2868.         compc = parsereg(thpat);
  2869.     }
  2870.     /* n holds the number of history line we have to search. */
  2871.     if (!n)
  2872.         n = -1;
  2873.  
  2874.     /* Now search the history. */
  2875.     while (n-- && (he = quietgethist(i--))) {
  2876.         int iwords;
  2877.         for (iwords = 0; iwords < he->nwords; iwords++) {
  2878.         h = he->text + he->words[iwords*2];
  2879.         e = he->text + he->words[iwords*2+1];
  2880.         hpatsav = *e;
  2881.         *e = '\0';
  2882.         /* We now have a word from the history, ignore it *
  2883.          * if it begins with a quote or `$'.              */
  2884.         if (*h != '\'' && *h != '"' && *h != '`' && *h != '$' &&
  2885.             (!compc || domatch(h, compc, 0)))
  2886.             /* Otherwise add it if it was matched. */
  2887.             addmatch(dupstring(h), NULL);
  2888.         if (hpatsav)
  2889.             *e = hpatsav;
  2890.         }
  2891.     }
  2892.     }
  2893.     if ((t = cc->mask & (CC_ARRAYS | CC_INTVARS | CC_ENVVARS | CC_SCALARS |
  2894.              CC_READONLYS | CC_SPECIALS | CC_PARAMS)))
  2895.     /* Add various flavours of parameters. */
  2896.     dumphashtable(paramtab, t);
  2897.     if ((t = cc->mask & CC_SHFUNCS))
  2898.     /* Add shell functions. */
  2899.     dumphashtable(shfunctab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
  2900.     if ((t = cc->mask & CC_BUILTINS))
  2901.     /* Add builtins. */
  2902.     dumphashtable(builtintab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
  2903.     if ((t = cc->mask & CC_EXTCMDS))
  2904.     /* Add external commands */
  2905.     dumphashtable(cmdnamtab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
  2906.     if ((t = cc->mask & CC_RESWDS))
  2907.     /* Add reserved words */
  2908.     dumphashtable(reswdtab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
  2909.     if ((t = cc->mask & (CC_ALREG | CC_ALGLOB)))
  2910.     /* Add the two types of aliases. */
  2911.     dumphashtable(aliastab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
  2912.  
  2913.     /* If we have no matches, ignore fignore. */
  2914.     if (empty(matches)) {
  2915.     matches = fmatches;
  2916.     firstm = ffirstm;
  2917.     shortest = fshortest;
  2918.     ab = fab;
  2919.     ae = fae;
  2920.     shortl = fshortl;
  2921.     }
  2922.  
  2923.     /* Make an array from the list of matches. */
  2924.     makearray(matches);
  2925.     PERMALLOC {
  2926.     amatches = arrdup(amatches);
  2927.     /* And quote the prefixes/suffixes. */
  2928.     if (hasspecial(s)) {
  2929.         zfree(lpre, lpl);
  2930.         zfree(lsuf, lsl);
  2931.         lpre = zalloc(lpl + 1);
  2932.         memcpy(lpre, s, lpl);
  2933.         lpre[lpl] = '\0';
  2934.         lsuf = ztrdup(s + offs);
  2935.         quotepresuf(&lpre);
  2936.         quotepresuf(&lsuf);
  2937.         untokenize(lpre);
  2938.         untokenize(lsuf);
  2939.     }
  2940.     quotepresuf(&fpre);
  2941.     quotepresuf(&fsuf);
  2942.     quotepresuf(&ppre);
  2943.     quotepresuf(&psuf);
  2944.     } LASTALLOC;
  2945.  
  2946.     /* Get the explanation string we will have to print. */
  2947.     expl = cc->explain;
  2948.  
  2949.     remsuffix = (cc->mask & CC_REMOVE);
  2950.     ccsuffix = cc->suffix;
  2951.  
  2952.     validlist = 1;
  2953.     if(nmatches && !errflag)
  2954.     return 0;
  2955.  
  2956.     if ((isf || cc->xor) && !parampre) {
  2957.     /* We found no matches, but there is a xor'ed completion: *
  2958.      * fine, so go back and continue with that compctl.       */
  2959.     errflag = 0;
  2960.     cc = cc->xor;
  2961.     isf = 0;
  2962.     wb = owb;
  2963.     we = owe;
  2964.     cs = ocs;
  2965.     strcpy((char *)line, (char *)ol);
  2966.     offs = oloffs;
  2967.     s = dupstring(os);
  2968.     free(amatches);
  2969.     zsfree(rpre);
  2970.     zsfree(rsuf);
  2971.     zsfree(lpre);
  2972.     zsfree(lsuf);
  2973.     zsfree(ppre);
  2974.     zsfree(psuf);
  2975.     zsfree(fpre);
  2976.     zsfree(fsuf);
  2977.     zsfree(prpre);
  2978.     zsfree(parampre);
  2979.     zsfree(qparampre);
  2980.     goto xorrec;
  2981.     }
  2982.  
  2983.     return 1;
  2984. }
  2985.  
  2986. /* Invalidate the completion list. */
  2987.  
  2988. /**/
  2989. void
  2990. invalidatelist(void)
  2991. {
  2992.     if(showinglist == -2)
  2993.     listmatches();
  2994.     if(validlist) {
  2995.     freearray(amatches);
  2996.     zsfree(rpre);
  2997.     zsfree(rsuf);
  2998.     zsfree(lpre);
  2999.     zsfree(lsuf);
  3000.     zsfree(ppre);
  3001.     zsfree(psuf);
  3002.     zsfree(fpre);
  3003.     zsfree(fsuf);
  3004.     zsfree(prpre);
  3005.     zsfree(parampre);
  3006.     zsfree(qparampre);
  3007.     if (ccmain != &cc_dummy)
  3008.         freecompctl(ccmain);
  3009.     }
  3010.     menucmp = showinglist = validlist = 0;
  3011. }
  3012.  
  3013. /* Get the words from a variable or a compctl -k list. */
  3014.  
  3015. /**/
  3016. char **
  3017. get_user_var(char *nam)
  3018. {
  3019.     if (!nam)
  3020.     return NULL;
  3021.     else if (*nam == '(') {
  3022.     /* It's a (...) list, not a parameter name. */
  3023.     char *ptr, *s, **uarr, **aptr;
  3024.     int count = 0, notempty = 0, brk = 0;
  3025.     LinkList arrlist = newlinklist();
  3026.  
  3027.     ptr = dupstring(nam);
  3028.     s = ptr + 1;
  3029.     while (*++ptr) {
  3030.         if (*ptr == '\\' && ptr[1])
  3031.         chuck(ptr), notempty = 1;
  3032.         else if (*ptr == ',' || inblank(*ptr) || *ptr == ')') {
  3033.         if (*ptr == ')')
  3034.             brk++;
  3035.         if (notempty) {
  3036.             *ptr = '\0';
  3037.             count++;
  3038.             if (*s == '\n')
  3039.             s++;
  3040.             addlinknode(arrlist, s);
  3041.         }
  3042.         s = ptr + 1;
  3043.         notempty = 0;
  3044.         } else {
  3045.         notempty = 1;
  3046.         if(*ptr == Meta)
  3047.             ptr++;
  3048.         }
  3049.         if (brk)
  3050.         break;
  3051.     }
  3052.     if (!brk || !count)
  3053.         return NULL;
  3054.     *ptr = '\0';
  3055.     aptr = uarr = (char **)ncalloc(sizeof(char *) * (count + 1));
  3056.  
  3057.     while ((*aptr++ = (char *)ugetnode(arrlist)));
  3058.     uarr[count] = NULL;
  3059.     return uarr;
  3060.     } else
  3061.     /* Otherwise it should be a parameter name. */
  3062.     return getaparam(nam);
  3063. }
  3064.  
  3065. /* This is strcmp with ignoring backslashes. */
  3066.  
  3067. /**/
  3068. int
  3069. strbpcmp(const void *a, const void *b)
  3070. {
  3071.     char *aa = *((char **)a), *bb = *((char **)b);
  3072.  
  3073.     while (*aa && *bb) {
  3074.     if (*aa == '\\')
  3075.         aa++;
  3076.     if (*bb == '\\')
  3077.         bb++;
  3078.     if (*aa != *bb)
  3079.         return (int)(*aa - *bb);
  3080.     if (*aa)
  3081.         aa++;
  3082.     if (*bb)
  3083.         bb++;
  3084.     }
  3085.     return (int)(*aa - *bb);
  3086. }
  3087.  
  3088. /* Make an array from a linked list */
  3089.  
  3090. /**/
  3091. void
  3092. makearray(LinkList l)
  3093. {
  3094.     char **ap, **bp, **cp;
  3095.     LinkNode nod;
  3096.  
  3097.     /* Build an array for the matches. */
  3098.     ap = amatches = (char **)ncalloc(((nmatches = countlinknodes(l)) + 1) *
  3099.                      sizeof(char *));
  3100.  
  3101.     /* And copy them into it. */
  3102.     for (nod = firstnode(l); nod; incnode(nod))
  3103.     *ap++ = (char *)getdata(nod);
  3104.     *ap = NULL;
  3105.  
  3106.     /* Now sort the array. */
  3107.     qsort((void *) amatches, nmatches, sizeof(char *),
  3108.            (int (*) _((const void *, const void *)))strbpcmp);
  3109.  
  3110.     /* And delete the ones that occur more than once. */
  3111.     for (ap = cp = amatches; *ap; ap++) {
  3112.     *cp++ = *ap;
  3113.     for (bp = ap; bp[1] && !strcmp(*ap, bp[1]); bp++);
  3114.     ap = bp;
  3115.     }
  3116.     *cp = NULL;
  3117.     nmatches = arrlen(amatches);
  3118. }
  3119.  
  3120. /* Handle the case were we found more than one match. */
  3121.  
  3122. /**/
  3123. void
  3124. do_ambiguous(void)
  3125. {
  3126.     int p = (usemenu || ispattern), atend = (cs == we);
  3127.     int inv = 0;
  3128.  
  3129.     menucmp = 0;
  3130.  
  3131.     /* If we have to insert the first match, call do_single().  This is *
  3132.      * how REC_EXACT takes effect.  We effectively turn the ambiguous   *
  3133.      * completion into an unambiguous one.                              */
  3134.     if (shortest && shortl == 0 && isset(RECEXACT) &&
  3135.     (usemenu == 0 || unset(AUTOMENU))) {
  3136.     do_single(shortest);
  3137.     invalidatelist();
  3138.     return;
  3139.     }
  3140.     /* Setting lastambig here means that the completion is ambiguous and *
  3141.      * AUTO_MENU might want to start a menu completion next time round,  *
  3142.      * but this might be overridden below if we can complete an          *
  3143.      * unambiguous prefix.                                               */
  3144.     lastambig = 1;
  3145.     if(p) {
  3146.     /* p is set if we are in a position to start using menu completion *
  3147.      * due to one of the menu completion options, or due to the        *
  3148.      * menu-complete-word command, or due to using GLOB_COMPLETE which *
  3149.      * does menu-style completion regardless of the setting of the     *
  3150.      * normal menu completion options.                                 */
  3151.     do_ambig_menu();
  3152.     } else {
  3153.     /* Sort-of general case: we have an ambiguous completion, and aren't *
  3154.      * starting menu completion or doing anything really weird.  We need *
  3155.      * to insert any unambiguous prefix and suffix, if possible.         */
  3156.     complexpect = 0;
  3157.     if(ab)
  3158.         inststrlen(firstm, 1, ab);
  3159.     if(ae && !atend)
  3160.         inststrlen(firstm + strlen(firstm) - ae, 0, ae);
  3161.     if(ab || (ae && !atend))
  3162.         inv = 1;
  3163.     /* If the LIST_AMBIGUOUS option (meaning roughly `show a list only *
  3164.      * if the completion is completely ambiguous') is set, and some    *
  3165.      * prefix was inserted, return now, bypassing the list-displaying  *
  3166.      * code.  On the way, invalidate the list and note that we don't   *
  3167.      * want to enter an AUTO_MENU imediately.                          */
  3168.     if(isset(LISTAMBIGUOUS) && inv) {
  3169.         invalidatelist();
  3170.         lastambig = 0;
  3171.         return;
  3172.     }
  3173.     }
  3174.     /* At this point, we might want a completion listing.  Show the listing *
  3175.      * if it is needed.                                                     */
  3176.     if (unset(NOLISTBEEP))
  3177.     feep();
  3178.     if (isset(AUTOLIST) && !amenu && !showinglist)
  3179.     showinglist = -2;
  3180.     if(inv)
  3181.     invalidatelist();
  3182. }
  3183.  
  3184. /* This is a stat that ignores backslashes in the filename.  The `ls' *
  3185.  * parameter says if we have to do lstat() or stat().  I think this   *
  3186.  * should instead be done by use of a general function to expand a    *
  3187.  * filename (stripping backslashes), combined with the actual         *
  3188.  * (l)stat().                                                         */
  3189.  
  3190. /**/
  3191. int
  3192. ztat(char *nam, struct stat *buf, int ls)
  3193. {
  3194.     char b[PATH_MAX], *p;
  3195.  
  3196.     for (p = b; p < b + sizeof(b) - 1 && *nam; nam++)
  3197.     if (*nam == '\\' && nam[1])
  3198.         *p++ = *++nam;
  3199.     else
  3200.         *p++ = *nam;
  3201.     *p = '\0';
  3202.  
  3203.     return ls ? lstat(b, buf) : stat(b, buf);
  3204. }
  3205.  
  3206. /* Insert a single match in the command line. */
  3207.  
  3208. /**/
  3209. void
  3210. do_single(char *str)
  3211. {
  3212.     int ccs, l, insc = 0, inscs = 0;
  3213.     char singlec = ' ';
  3214.  
  3215.     if (!ccsuffix || !(haswhat & HAS_SUFFIX) || !remsuffix)
  3216.     addedsuffix = 0;
  3217.  
  3218.     if (!menucur) {
  3219.     /* We are currently not in a menu-completion, *
  3220.      * so set the position variables.             */
  3221.     menuinsc = 0;
  3222.     if (ispattern) {
  3223.         cs = we;
  3224.         menupos = wb;
  3225.     } else
  3226.         menupos = cs;
  3227.     menuwe = (cs == we);
  3228.     if (ccsuffix && !(haswhat & HAS_SUFFIX)) {
  3229.         /* Add a compctl -S suffix if we have one. */
  3230.         if (*ccsuffix) {
  3231.         ccs = cs;
  3232.         cs = we;
  3233.         inststrlen(ccsuffix, menuwe, -1);
  3234.         menuend = cs;
  3235.         cs = ccs;
  3236.         if (remsuffix)
  3237.             /* addedsuffix is used by the key input handling  *
  3238.              * code to find out if it has to delete a suffix. */
  3239.             addedsuffix = strlen(ccsuffix);
  3240.         } else
  3241.         menuend = we;
  3242.  
  3243.         haswhat |= HAS_SUFFIX;
  3244.     } else
  3245.         menuend = we;
  3246.     }
  3247.     ccs = cs;
  3248.     /* If we are already in a menu-completion or if we have done a *
  3249.      * glob completion, we have to delete some of the stuff on the *
  3250.      * command line.                                               */
  3251.     if (menucur) {
  3252.     if (menuinsc) {
  3253.         cs = menuend;
  3254.         foredel(1);
  3255.     }
  3256.     l = menulen;
  3257.     } else if (ispattern)
  3258.     l = we - wb;
  3259.     else
  3260.     l = 0;
  3261.     cs = menupos;
  3262.     menuinsc = 0;
  3263.  
  3264.     if (l) {
  3265.     foredel(l);
  3266.     if (menuwe)
  3267.         ccs -= l;
  3268.     menuend -= l;
  3269.     }
  3270.     /* And than we insert the new string. */
  3271.     inststrlen(str, 1, menulen = strlen(str));
  3272.  
  3273.     /* And move the cursor and adjust the menuend variable. */
  3274.     if (menuwe)
  3275.     cs = ccs + menulen;
  3276.     menuend += menulen;
  3277.  
  3278.     if (!(haswhat & HAS_SUFFIX)) {
  3279.     /* There is no suffix, so we may add one. */
  3280.     if (!(haswhat & HAS_MISC) || (parampre && isset(AUTOPARAMSLASH))) {
  3281.         /* If we have only filenames or we completed a parameter name  *
  3282.          * and auto_param_slash is set, lets see if it is a directory. */
  3283.         char *p;
  3284.         struct stat buf;
  3285.  
  3286.         /* Build the path name. */
  3287.         if (ispattern || ic || parampre) {
  3288.         int ne = noerrs;
  3289.  
  3290.         noerrs = 1;
  3291.  
  3292.         if (parampre) {
  3293.             int pl = strlen(parampre);
  3294.             p = (char *) ncalloc(pl + strlen(lpre) + strlen(str) +
  3295.                      strlen(lsuf) + 1);
  3296.             sprintf(p, "%s%s%s%s", parampre, lpre, str, lsuf);
  3297.             if (pl && p[pl-1] == Inbrace)
  3298.             strcpy(p+pl-1, p+pl);
  3299.         }
  3300.         else if (ic) {
  3301.             p = (char *) ncalloc(strlen(ppre) + strlen(fpre) + strlen(str) +
  3302.                      strlen(fsuf) + strlen(psuf) + 2);
  3303.             sprintf(p, "%c%s%s%s%s%s", ic,
  3304.                 ppre, fpre, str, fsuf, psuf);
  3305.         }
  3306.         else
  3307.             p = dupstring(str);
  3308.         parsestr(p);
  3309.         if (ic)
  3310.             *p = ic;
  3311.         singsub(&p);
  3312.  
  3313.         noerrs = ne;
  3314.         } else {
  3315.         p = (char *) ncalloc((prpre ? strlen(prpre) : 0) + strlen(fpre) +
  3316.                      strlen(str) + strlen(fsuf) + strlen(psuf) + 3);
  3317.         sprintf(p, "%s%s%s%s%s",
  3318.             (prpre && *prpre) ? prpre : "./", fpre, str,
  3319.             fsuf, psuf);
  3320.         }
  3321.         /* And do the stat. */
  3322.         if (!ztat(p, &buf, 0) && (buf.st_mode & S_IFMT) == S_IFDIR) {
  3323.         /* It is a directory, so prepare to add *
  3324.          * the slash and set addedsuffix.       */
  3325.         singlec = '/';
  3326.         if (menuwe || isset(ALWAYSTOEND))
  3327.             addedsuffix = isset(AUTOREMOVESLASH) ? 1 : 0;
  3328.         }
  3329.     }
  3330.     if (menuend > ll)
  3331.         menuend = ll;
  3332.     if (menuend && ((((char)line[menuend - 1]) != singlec) ||
  3333.         (menuend > 1 && singlec == ' ' &&
  3334.           (line[menuend - 2] == '\\' || line[menuend - 2] == STOUC(Meta)))))
  3335.         if (parampre && singlec == '/' && ((char)line[menuend]) == '/')
  3336.         addedsuffix = 0;
  3337.         /* Now insert the slash or space if there is none already. */
  3338.         else {
  3339.         ccs = cs;
  3340.         cs = menuend;
  3341.         inststrlen((char *)&singlec, 1, 1);
  3342.         insc = 1;
  3343.         if (singlec != ' ')
  3344.             menuinsc = 1;
  3345.         inscs = cs;
  3346.         if (!menuwe)
  3347.             cs = ccs;
  3348.         }
  3349.     }
  3350.     /* Move to the end of the word if requested. */
  3351.     if (isset(ALWAYSTOEND) || menuwe)
  3352.     cs = menuend + (!(haswhat & HAS_SUFFIX) && insc);
  3353.     if (menucmp && singlec == ' ' && !(haswhat & HAS_SUFFIX)) {
  3354.     /* Get rid of the added space if we are doing menucompletion. */
  3355.     if (insc) {
  3356.         ccs = cs;
  3357.         cs = inscs;
  3358.         backdel(1);
  3359.         if (ccs != inscs)
  3360.           cs = ccs;
  3361.     } else
  3362.         cs--;
  3363.     }
  3364. }
  3365.  
  3366. /* This handles the beginning of menu-completion. */
  3367.  
  3368. /**/
  3369. void
  3370. do_ambig_menu(void)
  3371. {
  3372.     menucmp = 1;
  3373.     menucur = NULL;
  3374.     do_single(amatches[0]);
  3375.     menucur = amatches;
  3376. }
  3377.  
  3378. /* Return non-zero if s is a prefix of t. */
  3379.  
  3380. /**/
  3381. int
  3382. strpfx(char *s, char *t)
  3383. {
  3384.     while (*s && *s == *t)
  3385.     s++, t++;
  3386.     return !*s;
  3387. }
  3388.  
  3389. /* Return non-zero if s is a suffix of t. */
  3390.  
  3391. /**/
  3392. int
  3393. strsfx(char *s, char *t)
  3394. {
  3395.     int ls = strlen(s), lt = strlen(t);
  3396.  
  3397.     if (ls <= lt)
  3398.     return !strcmp(t + lt - ls, s);
  3399.     return 0;
  3400. }
  3401.  
  3402. /* Return the length of the common prefix of s and t. */
  3403.  
  3404. /**/
  3405. int
  3406. pfxlen(char *s, char *t)
  3407. {
  3408.     int i = 0;
  3409.  
  3410.     while (*s && *s == *t)
  3411.     s++, t++, i++;
  3412.     return i;
  3413. }
  3414.  
  3415. /* Return the length of the common suffix of s and t. */
  3416.  
  3417. /**/
  3418. int
  3419. sfxlen(char *s, char *t)
  3420. {
  3421.     if (*s && *t) {
  3422.     int i = 0;
  3423.     char *s2 = s + strlen(s) - 1, *t2 = t + strlen(t) - 1;
  3424.  
  3425.     while (s2 >= s && t2 >= t && *s2 == *t2)
  3426.         s2--, t2--, i++;
  3427.  
  3428.     return i;
  3429.     } else
  3430.     return 0;
  3431. }
  3432.  
  3433. /* This is used to print the explanation string. *
  3434.  * It returns the number of lines printed.       */
  3435.  
  3436. /**/
  3437. int
  3438. printfmt(char *fmt, int n, int dopr)
  3439. {
  3440.     char *p = fmt, nc[DIGBUFSIZE];
  3441.     int l = 0, cc = 0;
  3442.  
  3443.     for (; *p; p++) {
  3444.     /* Handle the `%' stuff (%% == %, %n == <number of matches>). */
  3445.     if (*p == '%') {
  3446.         if (*++p) {
  3447.         switch (*p) {
  3448.         case '%':
  3449.             if (dopr)
  3450.             putc('%', shout);
  3451.             cc++;
  3452.             break;
  3453.         case 'n':
  3454.             sprintf(nc, "%d", n);
  3455.             if (dopr)
  3456.             fprintf(shout, nc);
  3457.             cc += strlen(nc);
  3458.             break;
  3459.         }
  3460.         } else
  3461.         break;
  3462.     } else {
  3463.         cc++;
  3464.         if (*p == '\n') {
  3465.         l += 1 + (cc / columns);
  3466.         cc = 0;
  3467.         }
  3468.         if (dopr)
  3469.         putc(*p, shout);
  3470.     }
  3471.     }
  3472.  
  3473.     return l + (cc / columns);
  3474. }
  3475.  
  3476. /* List the matches.  Note that the list entries are metafied. */
  3477.  
  3478. /**/
  3479. void
  3480. listmatches(void)
  3481. {
  3482.     int longest = 1, fct, fw, colsz, t0, t1, ct, up, cl, xup = 0;
  3483.     int off, boff, nboff;
  3484.     int of = (isset(LISTTYPES) && !(haswhat & HAS_MISC));
  3485.     char **arr, **ap, sav;
  3486.     int nfpl, nfsl, nlpl, nlsl;
  3487.     int listmax = getiparam("LISTMAX");
  3488.  
  3489. #ifdef DEBUG
  3490.     /* Sanity check */
  3491.     if(!validlist) {
  3492.     trashzle();
  3493.     fputs("BUG: listmatches called with bogus list\n", shout);
  3494.     showinglist = 0;
  3495.     return;
  3496.     }
  3497. #endif
  3498.  
  3499.     /* Calculate lengths of prefixes/suffixes to be added */
  3500.     nfpl = fpre ? niceztrlen(fpre) : 0;
  3501.     nfsl = fsuf ? niceztrlen(fsuf) : 0;
  3502.     nlpl = lpre ? niceztrlen(lpre) : 0;
  3503.     nlsl = lsuf ? niceztrlen(lsuf) : 0;
  3504.  
  3505.     /* Calculate the lengths of the prefixes/suffixes we have to ignore
  3506.        during printing. */
  3507.     off = ispattern && ppre && *ppre &&
  3508.     !(haswhat & (HAS_MISC | HAS_PATHPAT)) ? strlen(ppre) : 0;
  3509.     boff = ispattern && psuf && *psuf &&
  3510.     !(haswhat & (HAS_MISC | HAS_PATHPAT)) ? strlen(psuf) : 0;
  3511.     nboff = ispattern && psuf && *psuf &&
  3512.     !(haswhat & (HAS_MISC | HAS_PATHPAT)) ? niceztrlen(psuf) : 0;
  3513.  
  3514.     /* When called from expandorcompleteprefix, we probably have to
  3515.        remove a space now. */
  3516.     if (remove_at >= 0) {
  3517.     int ocs = cs;
  3518.  
  3519.     cs = remove_at;
  3520.     deletechar();
  3521.     remove_at = -1;
  3522.     cs = ocs;
  3523.     }
  3524.  
  3525.     /* Set the cursor below the prompt. */
  3526.     trashzle();
  3527.     ct = nmatches;
  3528.     showinglist = 0;
  3529.  
  3530.     clearflag = (isset(USEZLE) && termok &&
  3531.          (isset(ALWAYSLASTPROMPT) && zmult == 1)) ||
  3532.     (unset(ALWAYSLASTPROMPT) && zmult != 1);
  3533.  
  3534.     arr = amatches;
  3535.  
  3536.     /* Calculate the column width, the number of columns and the number
  3537.        of lines. */
  3538.     for (ap = arr; *ap; ap++)
  3539.     if ((cl = niceztrlen(*ap + off) - nboff +
  3540.          (ispattern ? 0 :
  3541.           (!(haswhat & HAS_MISC) ? nfpl + nfsl : nlpl + nlsl))) > longest)
  3542.         longest = cl;
  3543.     if (of)
  3544.     longest++;
  3545.  
  3546.     fw = longest + 2;
  3547.     fct = (columns + 1) / fw;
  3548.     if (fct == 0) {
  3549.     fct = 1;
  3550.     colsz = ct;
  3551.     up = colsz + nlnct - clearflag;
  3552.     for (ap = arr; *ap; ap++)
  3553.         up += (niceztrlen(*ap + off) - nboff + of +
  3554.         (ispattern ? 0 :
  3555.         (!(haswhat & HAS_MISC) ? nfpl + nfsl : nlpl + nlsl))) / columns;
  3556.     } else {
  3557.     colsz = (ct + fct - 1) / fct;
  3558.     up = colsz + nlnct - clearflag;
  3559.     }
  3560.  
  3561.     /* Print the explanation string, if any. */
  3562.     if (expl) {
  3563.     xup = printfmt(expl, ct, 1) + 1;
  3564.     putc('\n', shout);
  3565.     up += xup;
  3566.     }
  3567.  
  3568.     /* Maybe we have to ask if the user wants to see the list. */
  3569.     if ((listmax && ct > listmax) || (!listmax && up >= lines)) {
  3570.     int qup;
  3571.     setterm();
  3572.     qup = printfmt("zsh: do you wish to see all %n possibilities? ", ct, 1);
  3573.     fflush(shout);
  3574.     if (getzlequery() != 'y') {
  3575.         if (clearflag) {
  3576.         putc('\r', shout);
  3577.         tcmultout(TCUP, TCMULTUP, qup);
  3578.         if (tccan(TCCLEAREOD))
  3579.             tcout(TCCLEAREOD);
  3580.         tcmultout(TCUP, TCMULTUP, nlnct + xup);
  3581.         } else
  3582.         putc('\n', shout);
  3583.         return;
  3584.     }
  3585.     if (clearflag) {
  3586.         putc('\r', shout);
  3587.         tcmultout(TCUP, TCMULTUP, qup);
  3588.         if (tccan(TCCLEAREOD))
  3589.         tcout(TCCLEAREOD);
  3590.     } else
  3591.         putc('\n', shout);
  3592.     settyinfo(&shttyinfo);
  3593.     }
  3594.  
  3595.     /* Now print the matches. */
  3596.     for (t1 = 0; t1 != colsz; t1++) {
  3597.     ap = arr + t1;
  3598.     if (of) {
  3599.         /* We have to print the file types. */
  3600.         while (*ap) {
  3601.         int t2;
  3602.         char *pb;
  3603.         struct stat buf;
  3604.  
  3605.         /* Build the path name for the stat. */
  3606.         if (ispattern) {
  3607.             int cut = strlen(*ap) - boff;
  3608.  
  3609.             sav = ap[0][cut];
  3610.             ap[0][cut] = '\0';
  3611.             nicezputs(*ap + off, shout);
  3612.             t2 = niceztrlen(*ap + off);
  3613.             ap[0][cut] = sav;
  3614.             pb = *ap;
  3615.         } else {
  3616.             nicezputs(fpre, shout);
  3617.             nicezputs(*ap, shout);
  3618.             nicezputs(fsuf, shout);
  3619.             t2 = nfpl + niceztrlen(*ap) + nfsl;
  3620.             pb = (char *) ncalloc((prpre ? strlen(prpre) : 0) + 3 +
  3621.                       strlen(fpre) + strlen(*ap) + strlen(fsuf));
  3622.             sprintf(pb, "%s%s%s%s",
  3623.                 (prpre && *prpre) ? prpre : "./", fpre, *ap, fsuf);
  3624.         }
  3625.         if (ztat(pb, &buf, 1))
  3626.             putc(' ', shout);
  3627.         else
  3628.             /* Print the file type character. */
  3629.             putc(file_type(buf.st_mode), shout);
  3630.         for (t0 = colsz; t0 && *ap; t0--, ap++);
  3631.         if (*ap)
  3632.             /* And add spaces to make the columns aligned. */
  3633.             for (++t2; t2 < fw; t2++)
  3634.             putc(' ', shout);
  3635.         }
  3636.     } else
  3637.         while (*ap) {
  3638.         int t2;
  3639.  
  3640.         if (ispattern) {
  3641.             int cut = strlen(*ap) - boff;
  3642.  
  3643.             sav = ap[0][cut];
  3644.             ap[0][cut] = '\0';
  3645.             nicezputs(*ap + off, shout);
  3646.             t2 = niceztrlen(*ap + off);
  3647.             ap[0][cut] = sav;
  3648.         } else if (!(haswhat & HAS_MISC)) {
  3649.             nicezputs(fpre, shout);
  3650.             nicezputs(*ap, shout);
  3651.             nicezputs(fsuf, shout);
  3652.             t2 = nfpl + niceztrlen(*ap) + nfsl;
  3653.         } else {
  3654.             nicezputs(lpre, shout);
  3655.             nicezputs(*ap, shout);
  3656.             nicezputs(lsuf, shout);
  3657.             t2 = nlpl + niceztrlen(*ap) + nlsl;
  3658.         }
  3659.         for (t0 = colsz; t0 && *ap; t0--, ap++);
  3660.         if (*ap)
  3661.             for (; t2 < fw; t2++)
  3662.             putc(' ', shout);
  3663.         }
  3664.     if (t1 != colsz - 1 || !clearflag)
  3665.         putc('\n', shout);
  3666.     }
  3667.     if (clearflag)
  3668.     /* Move the cursor up to the prompt, if always_last_prompt *
  3669.      * is set and all that...                                  */
  3670.     if (up < lines) {
  3671.         tcmultout(TCUP, TCMULTUP, up);
  3672.         showinglist = -1;
  3673.     } else
  3674.         clearflag = 0, putc('\n', shout);
  3675. }
  3676.  
  3677. /* This is used to print expansions. */
  3678.  
  3679. /**/
  3680. void
  3681. listlist(LinkList l)
  3682. {
  3683.     int hw = haswhat, ip = ispattern;
  3684.     char *lp = lpre, *ls = lsuf;
  3685.     int nm = nmatches, vl = validlist;
  3686.     char **am = amatches;
  3687.     char *ex = expl;
  3688.  
  3689.     haswhat = HAS_MISC;
  3690.     ispattern = 0;
  3691.     validlist = 1;
  3692.     lpre = lsuf = "";
  3693.     expl = NULL;
  3694.  
  3695.     makearray(l);
  3696.     listmatches();
  3697.     showinglist = 0;
  3698.  
  3699.     expl = ex;
  3700.     amatches = am;
  3701.     nmatches = nm;
  3702.     validlist = vl;
  3703.     lpre = lp;
  3704.     lsuf = ls;
  3705.     ispattern = ip;
  3706.     haswhat = hw;
  3707. }
  3708.  
  3709. /* And this is used to print select lists.  Hm, this function should *
  3710.  * probably be move to loop.c.                                       */
  3711.  
  3712. /**/
  3713. void
  3714. selectlist(LinkList l)
  3715. {
  3716.     int longest = 1, fct, fw = 0, colsz, t0, t1, ct;
  3717.     LinkNode n;
  3718.     char **arr, **ap;
  3719.  
  3720.     trashzle();
  3721.     ct = countlinknodes(l);
  3722.     ap = arr = (char **)alloc((countlinknodes(l) + 1) * sizeof(char **));
  3723.  
  3724.     for (n = (LinkNode) firstnode(l); n; incnode(n))
  3725.     *ap++ = (char *)getdata(n);
  3726.     *ap = NULL;
  3727.     for (ap = arr; *ap; ap++)
  3728.     if (strlen(*ap) > longest)
  3729.         longest = strlen(*ap);
  3730.     t0 = ct;
  3731.     longest++;
  3732.     while (t0)
  3733.     t0 /= 10, longest++;
  3734.     /* to compensate for added ')' */
  3735.     fct = (columns - 1) / (longest + 3);
  3736.     if (fct == 0)
  3737.     fct = 1;
  3738.     else
  3739.     fw = (columns - 1) / fct;
  3740.     colsz = (ct + fct - 1) / fct;
  3741.     for (t1 = 0; t1 != colsz; t1++) {
  3742.     ap = arr + t1;
  3743.     do {
  3744.         int t2 = strlen(*ap) + 2, t3;
  3745.  
  3746.         fprintf(stderr, "%d) %s", t3 = ap - arr + 1, *ap);
  3747.         while (t3)
  3748.         t2++, t3 /= 10;
  3749.         for (; t2 < fw; t2++)
  3750.         fputc(' ', stderr);
  3751.         for (t0 = colsz; t0 && *ap; t0--, ap++);
  3752.     }
  3753.     while (*ap);
  3754.     fputc('\n', stderr);
  3755.     }
  3756.  
  3757.  /* Below is a simple attempt at doing it the Korn Way..
  3758.        ap = arr;
  3759.        t0 = 0;
  3760.        do {
  3761.            t0++;
  3762.            fprintf(stderr,"%d) %s\n",t0,*ap);
  3763.            ap++;
  3764.        }
  3765.        while (*ap);*/
  3766.     fflush(stderr);
  3767. }
  3768.  
  3769. /* Expand the history references. */
  3770.  
  3771. /**/
  3772. int
  3773. doexpandhist(void)
  3774. {
  3775.     unsigned char *ol;
  3776.     int oll, ocs, ne = noerrs, err;
  3777.  
  3778.     DPUTS(useheap, "BUG: useheap in doexpandhist()");
  3779.     HEAPALLOC {
  3780.     pushheap();
  3781.     metafy_line();
  3782.     oll = ll;
  3783.     ocs = cs;
  3784.     ol = (unsigned char *)dupstring((char *)line);
  3785.     expanding = 1;
  3786.     excs = cs;
  3787.     ll = cs = 0;
  3788.     lexsave();
  3789.     inpush((char *) ol, 0);  /* We push ol as it will remain unchanged */
  3790.     strinbeg();
  3791.     noaliases = 1;
  3792.     noerrs = 1;
  3793.     exlast = inbufct;
  3794.     do {
  3795.         ctxtlex();
  3796.     } while (tok != ENDINPUT && tok != LEXERR);
  3797.     stophist = 2;
  3798.     while (!lexstop)
  3799.         hgetc();
  3800.     /* We have to save errflags because it's reset in lexrestore. Since  *
  3801.      * noerrs was set to 1 errflag is true if there was a habort() which *
  3802.      * means that the expanded string is unusable.                       */
  3803.     err = errflag;
  3804.     noerrs = ne;
  3805.     noaliases = 0;
  3806.     strinend();
  3807.     inpop();
  3808.     zleparse = 0;
  3809.     lexrestore();
  3810.     expanding = 0;
  3811.  
  3812.     if (!err) {
  3813.         cs = excs;
  3814.         if (strcmp((char *)line, (char *)ol)) {
  3815.         unmetafy_line();
  3816.         /* For vi mode -- reset the beginning-of-insertion pointer   *
  3817.          * to the beginning of the line.  This seems a little silly, *
  3818.          * if we are, for example, expanding "exec !!".              */
  3819.         if (viinsbegin > findbol())
  3820.             viinsbegin = findbol();
  3821.         popheap();
  3822.         LASTALLOC_RETURN 1;
  3823.         }
  3824.     }
  3825.  
  3826.     strcpy((char *)line, (char *)ol);
  3827.     ll = oll;
  3828.     cs = ocs;
  3829.     unmetafy_line();
  3830.  
  3831.     popheap();
  3832.     } LASTALLOC;
  3833.     return 0;
  3834. }
  3835.  
  3836. /**/
  3837. void
  3838. magicspace(void)
  3839. {
  3840.     c = ' ';
  3841.     selfinsert();
  3842.     doexpandhist();
  3843. }
  3844.  
  3845. /**/
  3846. void
  3847. expandhistory(void)
  3848. {
  3849.     if (!doexpandhist())
  3850.     feep();
  3851. }
  3852.  
  3853. static int cmdwb, cmdwe;
  3854.  
  3855. /**/
  3856. char *
  3857. getcurcmd(void)
  3858. {
  3859.     int curlincmd;
  3860.     char *s = NULL;
  3861.  
  3862.     DPUTS(useheap, "BUG: useheap in getcurcmd()");
  3863.     HEAPALLOC {
  3864.     zleparse = 1;
  3865.     lexsave();
  3866.     inpush(dupstrspace((char *) line), 0);
  3867.     strinbeg();
  3868.     pushheap();
  3869.     do {
  3870.         curlincmd = incmdpos;
  3871.         ctxtlex();
  3872.         if (tok == ENDINPUT || tok == LEXERR)
  3873.         break;
  3874.         if (tok == STRING && curlincmd) {
  3875.         zsfree(s);
  3876.         s = ztrdup(tokstr);
  3877.         cmdwb = ll - wordbeg;
  3878.         cmdwe = ll + 1 - inbufct;
  3879.         }
  3880.     }
  3881.     while (tok != ENDINPUT && tok != LEXERR && zleparse);
  3882.     popheap();
  3883.     strinend();
  3884.     inpop();
  3885.     errflag = zleparse = 0;
  3886.     lexrestore();
  3887.     } LASTALLOC;
  3888.     return s;
  3889. }
  3890.  
  3891. /**/
  3892. void
  3893. processcmd(void)
  3894. {
  3895.     char *s, *t;
  3896.  
  3897.     s = getcurcmd();
  3898.     if (!s) {
  3899.     feep();
  3900.     return;
  3901.     }
  3902.     t = zlecmds[bindk].name;
  3903.     zmult = 1;
  3904.     PERMALLOC {
  3905.     pushline();
  3906.     } LASTALLOC;
  3907.     sizeline(strlen(s) + strlen(t) + 1);
  3908.     strcpy((char *)line, t);
  3909.     strcat((char *)line, " ");
  3910.     cs = ll = strlen((char *)line);
  3911.     inststr(s);
  3912.     zsfree(s);
  3913.     done = 1;
  3914. }
  3915.  
  3916. /**/
  3917. void
  3918. expandcmdpath(void)
  3919. {
  3920.     int oldcs = cs, na = noaliases;
  3921.     char *s, *str;
  3922.  
  3923.     noaliases = 1;
  3924.     s = getcurcmd();
  3925.     noaliases = na;
  3926.     if (!s || cmdwb < 0 || cmdwe < cmdwb) {
  3927.     feep();
  3928.     return;
  3929.     }
  3930.     str = findcmd(s);
  3931.     zsfree(s);
  3932.     if (!str) {
  3933.     feep();
  3934.     return;
  3935.     }
  3936.     cs = cmdwb;
  3937.     foredel(cmdwe - cmdwb);
  3938.     spaceinline(strlen(str));
  3939.     strncpy((char *)line + cs, str, strlen(str));
  3940.     cs = oldcs;
  3941.     if (cs >= cmdwe - 1)
  3942.     cs += cmdwe - cmdwb + strlen(str);
  3943.     if (cs > ll)
  3944.     cs = ll;
  3945.     zsfree(str);
  3946. }
  3947.  
  3948. /* Extra function added by AR Iano-Fletcher. */
  3949. /* This is a expand/complete in the vein of wash. */
  3950.  
  3951. /**/
  3952. void
  3953. expandorcompleteprefix(void)
  3954. {
  3955.     /* global c is the current character typed. */
  3956.     int csafe = c;
  3957.  
  3958.     /* insert a space and backspace. */
  3959.     c = ' ';
  3960.     selfinsert();        /* insert the extra character */
  3961.     forwardchar();        /* move towards beginning */
  3962.     
  3963.     remove_at = cs;
  3964.  
  3965.     /* do the expansion/completion. */
  3966.     c = csafe;
  3967.     zmult = 1;
  3968.     expandorcomplete();        /* complete. */
  3969.     zmult = -1;
  3970.  
  3971.     /* remove the inserted space. */
  3972.     if (remove_at >= 0) {
  3973.     backwardchar();        /* move towards ends */
  3974.     deletechar();        /* delete the added space. */
  3975.     }
  3976.     remove_at = -1;
  3977. }
  3978.